blob: f21308f67a61e60c9eef710f5802401c96eb2c76 [file] [log] [blame]
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000030#if V8_TARGET_ARCH_IA32
ricow@chromium.org65fae842010-08-25 15:26:24 +000031
32#include "bootstrapper.h"
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000033#include "code-stubs.h"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000034#include "isolate.h"
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000035#include "jsregexp.h"
ricow@chromium.org65fae842010-08-25 15:26:24 +000036#include "regexp-macro-assembler.h"
danno@chromium.org94b0d6f2013-02-04 13:33:20 +000037#include "runtime.h"
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000038#include "stub-cache.h"
erikcorry0ad885c2011-11-21 13:51:57 +000039#include "codegen.h"
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000040#include "runtime.h"
ricow@chromium.org65fae842010-08-25 15:26:24 +000041
42namespace v8 {
43namespace internal {
44
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000045
verwaest@chromium.org662436e2013-08-28 08:41:27 +000046void FastNewClosureStub::InitializeInterfaceDescriptor(
47 Isolate* isolate,
48 CodeStubInterfaceDescriptor* descriptor) {
49 static Register registers[] = { ebx };
50 descriptor->register_param_count_ = 1;
51 descriptor->register_params_ = registers;
52 descriptor->deoptimization_handler_ =
53 Runtime::FunctionForId(Runtime::kNewClosureFromStubFailure)->entry;
54}
55
56
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +000057void FastNewContextStub::InitializeInterfaceDescriptor(
58 Isolate* isolate,
59 CodeStubInterfaceDescriptor* descriptor) {
60 static Register registers[] = { edi };
61 descriptor->register_param_count_ = 1;
62 descriptor->register_params_ = registers;
63 descriptor->deoptimization_handler_ = NULL;
64}
65
66
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +000067void ToNumberStub::InitializeInterfaceDescriptor(
68 Isolate* isolate,
69 CodeStubInterfaceDescriptor* descriptor) {
70 static Register registers[] = { eax };
71 descriptor->register_param_count_ = 1;
72 descriptor->register_params_ = registers;
73 descriptor->deoptimization_handler_ = NULL;
74}
75
76
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +000077void NumberToStringStub::InitializeInterfaceDescriptor(
78 Isolate* isolate,
79 CodeStubInterfaceDescriptor* descriptor) {
80 static Register registers[] = { eax };
81 descriptor->register_param_count_ = 1;
82 descriptor->register_params_ = registers;
bmeurer@chromium.orge7a07452013-10-21 13:27:29 +000083 descriptor->deoptimization_handler_ =
84 Runtime::FunctionForId(Runtime::kNumberToString)->entry;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +000085}
86
87
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000088void FastCloneShallowArrayStub::InitializeInterfaceDescriptor(
89 Isolate* isolate,
90 CodeStubInterfaceDescriptor* descriptor) {
91 static Register registers[] = { eax, ebx, ecx };
92 descriptor->register_param_count_ = 3;
93 descriptor->register_params_ = registers;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000094 descriptor->deoptimization_handler_ =
machenbach@chromium.org37be4082013-11-26 13:50:38 +000095 Runtime::FunctionForId(Runtime::kCreateArrayLiteralStubBailout)->entry;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000096}
97
98
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +000099void FastCloneShallowObjectStub::InitializeInterfaceDescriptor(
100 Isolate* isolate,
101 CodeStubInterfaceDescriptor* descriptor) {
102 static Register registers[] = { eax, ebx, ecx, edx };
103 descriptor->register_param_count_ = 4;
104 descriptor->register_params_ = registers;
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +0000105 descriptor->deoptimization_handler_ =
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000106 Runtime::FunctionForId(Runtime::kCreateObjectLiteral)->entry;
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +0000107}
108
109
danno@chromium.orgbee51992013-07-10 14:57:15 +0000110void CreateAllocationSiteStub::InitializeInterfaceDescriptor(
111 Isolate* isolate,
112 CodeStubInterfaceDescriptor* descriptor) {
113 static Register registers[] = { ebx };
114 descriptor->register_param_count_ = 1;
115 descriptor->register_params_ = registers;
116 descriptor->deoptimization_handler_ = NULL;
117}
118
119
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000120void KeyedLoadFastElementStub::InitializeInterfaceDescriptor(
121 Isolate* isolate,
122 CodeStubInterfaceDescriptor* descriptor) {
123 static Register registers[] = { edx, ecx };
124 descriptor->register_param_count_ = 2;
125 descriptor->register_params_ = registers;
126 descriptor->deoptimization_handler_ =
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000127 FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000128}
129
130
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000131void KeyedLoadDictionaryElementStub::InitializeInterfaceDescriptor(
132 Isolate* isolate,
133 CodeStubInterfaceDescriptor* descriptor) {
134 static Register registers[] = { edx, ecx };
135 descriptor->register_param_count_ = 2;
136 descriptor->register_params_ = registers;
137 descriptor->deoptimization_handler_ =
138 FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
139}
140
141
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000142void LoadFieldStub::InitializeInterfaceDescriptor(
143 Isolate* isolate,
144 CodeStubInterfaceDescriptor* descriptor) {
145 static Register registers[] = { edx };
146 descriptor->register_param_count_ = 1;
147 descriptor->register_params_ = registers;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000148 descriptor->deoptimization_handler_ = NULL;
149}
150
151
152void KeyedLoadFieldStub::InitializeInterfaceDescriptor(
153 Isolate* isolate,
154 CodeStubInterfaceDescriptor* descriptor) {
155 static Register registers[] = { edx };
156 descriptor->register_param_count_ = 1;
157 descriptor->register_params_ = registers;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000158 descriptor->deoptimization_handler_ = NULL;
159}
160
161
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000162void KeyedArrayCallStub::InitializeInterfaceDescriptor(
163 Isolate* isolate,
164 CodeStubInterfaceDescriptor* descriptor) {
165 static Register registers[] = { ecx };
166 descriptor->register_param_count_ = 1;
167 descriptor->register_params_ = registers;
168 descriptor->continuation_type_ = TAIL_CALL_CONTINUATION;
169 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
170 descriptor->deoptimization_handler_ =
171 FUNCTION_ADDR(KeyedCallIC_MissFromStubFailure);
172}
173
174
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000175void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
176 Isolate* isolate,
177 CodeStubInterfaceDescriptor* descriptor) {
178 static Register registers[] = { edx, ecx, eax };
179 descriptor->register_param_count_ = 3;
180 descriptor->register_params_ = registers;
181 descriptor->deoptimization_handler_ =
182 FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure);
183}
184
185
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000186void TransitionElementsKindStub::InitializeInterfaceDescriptor(
187 Isolate* isolate,
188 CodeStubInterfaceDescriptor* descriptor) {
189 static Register registers[] = { eax, ebx };
190 descriptor->register_param_count_ = 2;
191 descriptor->register_params_ = registers;
192 descriptor->deoptimization_handler_ =
193 Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry;
194}
195
196
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000197static void InitializeArrayConstructorDescriptor(
198 Isolate* isolate,
199 CodeStubInterfaceDescriptor* descriptor,
200 int constant_stack_parameter_count) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000201 // register state
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000202 // eax -- number of arguments
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000203 // edi -- function
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +0000204 // ebx -- allocation site with elements kind
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000205 static Register registers_variable_args[] = { edi, ebx, eax };
206 static Register registers_no_args[] = { edi, ebx };
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000207
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000208 if (constant_stack_parameter_count == 0) {
209 descriptor->register_param_count_ = 2;
210 descriptor->register_params_ = registers_no_args;
211 } else {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000212 // stack param count needs (constructor pointer, and single argument)
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000213 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000214 descriptor->stack_parameter_count_ = eax;
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000215 descriptor->register_param_count_ = 3;
216 descriptor->register_params_ = registers_variable_args;
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000217 }
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000218
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000219 descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000220 descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000221 descriptor->deoptimization_handler_ =
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000222 Runtime::FunctionForId(Runtime::kArrayConstructor)->entry;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000223}
224
225
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000226static void InitializeInternalArrayConstructorDescriptor(
227 Isolate* isolate,
228 CodeStubInterfaceDescriptor* descriptor,
229 int constant_stack_parameter_count) {
230 // register state
231 // eax -- number of arguments
232 // edi -- constructor function
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000233 static Register registers_variable_args[] = { edi, eax };
234 static Register registers_no_args[] = { edi };
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000235
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000236 if (constant_stack_parameter_count == 0) {
237 descriptor->register_param_count_ = 1;
238 descriptor->register_params_ = registers_no_args;
239 } else {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000240 // stack param count needs (constructor pointer, and single argument)
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000241 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000242 descriptor->stack_parameter_count_ = eax;
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000243 descriptor->register_param_count_ = 2;
244 descriptor->register_params_ = registers_variable_args;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000245 }
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000246
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000247 descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000248 descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
249 descriptor->deoptimization_handler_ =
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000250 Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000251}
252
253
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000254void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor(
255 Isolate* isolate,
256 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000257 InitializeArrayConstructorDescriptor(isolate, descriptor, 0);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000258}
259
260
261void ArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor(
262 Isolate* isolate,
263 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000264 InitializeArrayConstructorDescriptor(isolate, descriptor, 1);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000265}
266
267
268void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
269 Isolate* isolate,
270 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000271 InitializeArrayConstructorDescriptor(isolate, descriptor, -1);
272}
273
274
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000275void InternalArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor(
276 Isolate* isolate,
277 CodeStubInterfaceDescriptor* descriptor) {
278 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 0);
279}
280
281
282void InternalArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor(
283 Isolate* isolate,
284 CodeStubInterfaceDescriptor* descriptor) {
285 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 1);
286}
287
288
289void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
290 Isolate* isolate,
291 CodeStubInterfaceDescriptor* descriptor) {
292 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, -1);
293}
294
295
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000296void CompareNilICStub::InitializeInterfaceDescriptor(
297 Isolate* isolate,
298 CodeStubInterfaceDescriptor* descriptor) {
299 static Register registers[] = { eax };
300 descriptor->register_param_count_ = 1;
301 descriptor->register_params_ = registers;
302 descriptor->deoptimization_handler_ =
303 FUNCTION_ADDR(CompareNilIC_Miss);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000304 descriptor->SetMissHandler(
305 ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000306}
307
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000308void ToBooleanStub::InitializeInterfaceDescriptor(
309 Isolate* isolate,
310 CodeStubInterfaceDescriptor* descriptor) {
311 static Register registers[] = { eax };
312 descriptor->register_param_count_ = 1;
313 descriptor->register_params_ = registers;
314 descriptor->deoptimization_handler_ =
315 FUNCTION_ADDR(ToBooleanIC_Miss);
316 descriptor->SetMissHandler(
317 ExternalReference(IC_Utility(IC::kToBooleanIC_Miss), isolate));
318}
319
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000320
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000321void StoreGlobalStub::InitializeInterfaceDescriptor(
322 Isolate* isolate,
323 CodeStubInterfaceDescriptor* descriptor) {
324 static Register registers[] = { edx, ecx, eax };
325 descriptor->register_param_count_ = 3;
326 descriptor->register_params_ = registers;
327 descriptor->deoptimization_handler_ =
328 FUNCTION_ADDR(StoreIC_MissFromStubFailure);
329}
330
331
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000332void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
333 Isolate* isolate,
334 CodeStubInterfaceDescriptor* descriptor) {
335 static Register registers[] = { eax, ebx, ecx, edx };
336 descriptor->register_param_count_ = 4;
337 descriptor->register_params_ = registers;
338 descriptor->deoptimization_handler_ =
339 FUNCTION_ADDR(ElementsTransitionAndStoreIC_Miss);
340}
341
342
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +0000343void BinaryOpICStub::InitializeInterfaceDescriptor(
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +0000344 Isolate* isolate,
345 CodeStubInterfaceDescriptor* descriptor) {
346 static Register registers[] = { edx, eax };
347 descriptor->register_param_count_ = 2;
348 descriptor->register_params_ = registers;
349 descriptor->deoptimization_handler_ = FUNCTION_ADDR(BinaryOpIC_Miss);
350 descriptor->SetMissHandler(
351 ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate));
352}
353
354
ulan@chromium.org0f13e742014-01-03 15:51:11 +0000355void BinaryOpWithAllocationSiteStub::InitializeInterfaceDescriptor(
356 Isolate* isolate,
357 CodeStubInterfaceDescriptor* descriptor) {
358 static Register registers[] = { ecx, edx, eax };
359 descriptor->register_param_count_ = 3;
360 descriptor->register_params_ = registers;
361 descriptor->deoptimization_handler_ =
362 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite);
363}
364
365
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +0000366void StringAddStub::InitializeInterfaceDescriptor(
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000367 Isolate* isolate,
368 CodeStubInterfaceDescriptor* descriptor) {
369 static Register registers[] = { edx, eax };
370 descriptor->register_param_count_ = 2;
371 descriptor->register_params_ = registers;
372 descriptor->deoptimization_handler_ =
373 Runtime::FunctionForId(Runtime::kStringAdd)->entry;
374}
375
376
machenbach@chromium.org26ca35c2014-01-16 08:22:55 +0000377void CallDescriptors::InitializeForIsolate(Isolate* isolate) {
378 {
379 CallInterfaceDescriptor* descriptor =
380 isolate->call_descriptor(Isolate::ArgumentAdaptorCall);
381 static Register registers[] = { edi, // JSFunction
382 esi, // context
383 eax, // actual number of arguments
384 ebx, // expected number of arguments
385 };
386 static Representation representations[] = {
387 Representation::Tagged(), // JSFunction
388 Representation::Tagged(), // context
389 Representation::Integer32(), // actual number of arguments
390 Representation::Integer32(), // expected number of arguments
391 };
392 descriptor->register_param_count_ = 4;
393 descriptor->register_params_ = registers;
394 descriptor->param_representations_ = representations;
395 }
396 {
397 CallInterfaceDescriptor* descriptor =
398 isolate->call_descriptor(Isolate::KeyedCall);
399 static Register registers[] = { esi, // context
400 ecx, // key
401 };
402 static Representation representations[] = {
403 Representation::Tagged(), // context
404 Representation::Tagged(), // key
405 };
406 descriptor->register_param_count_ = 2;
407 descriptor->register_params_ = registers;
408 descriptor->param_representations_ = representations;
409 }
410 {
411 CallInterfaceDescriptor* descriptor =
412 isolate->call_descriptor(Isolate::NamedCall);
413 static Register registers[] = { esi, // context
414 ecx, // name
415 };
416 static Representation representations[] = {
417 Representation::Tagged(), // context
418 Representation::Tagged(), // name
419 };
420 descriptor->register_param_count_ = 2;
421 descriptor->register_params_ = registers;
422 descriptor->param_representations_ = representations;
423 }
424}
425
426
ricow@chromium.org65fae842010-08-25 15:26:24 +0000427#define __ ACCESS_MASM(masm)
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000428
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000429
430void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) {
431 // Update the static counter each time a new code stub is generated.
432 Isolate* isolate = masm->isolate();
433 isolate->counters()->code_stubs()->Increment();
434
435 CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate);
436 int param_count = descriptor->register_param_count_;
437 {
438 // Call the runtime system in a fresh internal frame.
439 FrameScope scope(masm, StackFrame::INTERNAL);
440 ASSERT(descriptor->register_param_count_ == 0 ||
441 eax.is(descriptor->register_params_[param_count - 1]));
442 // Push arguments
443 for (int i = 0; i < param_count; ++i) {
444 __ push(descriptor->register_params_[i]);
445 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000446 ExternalReference miss = descriptor->miss_handler();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000447 __ CallExternalReference(miss, descriptor->register_param_count_);
448 }
449
450 __ ret(0);
451}
452
453
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000454void FastNewBlockContextStub::Generate(MacroAssembler* masm) {
455 // Stack layout on entry:
456 //
457 // [esp + (1 * kPointerSize)]: function
458 // [esp + (2 * kPointerSize)]: serialized scope info
459
460 // Try to allocate the context in new space.
461 Label gc;
462 int length = slots_ + Context::MIN_CONTEXT_SLOTS;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000463 __ Allocate(FixedArray::SizeFor(length), eax, ebx, ecx, &gc, TAG_OBJECT);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000464
465 // Get the function or sentinel from the stack.
466 __ mov(ecx, Operand(esp, 1 * kPointerSize));
467
468 // Get the serialized scope info from the stack.
469 __ mov(ebx, Operand(esp, 2 * kPointerSize));
470
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000471 // Set up the object header.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000472 Factory* factory = masm->isolate()->factory();
473 __ mov(FieldOperand(eax, HeapObject::kMapOffset),
474 factory->block_context_map());
475 __ mov(FieldOperand(eax, Context::kLengthOffset),
476 Immediate(Smi::FromInt(length)));
477
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000478 // If this block context is nested in the native context we get a smi
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000479 // sentinel instead of a function. The block context should get the
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000480 // canonical empty function of the native context as its closure which
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000481 // we still have to look up.
482 Label after_sentinel;
483 __ JumpIfNotSmi(ecx, &after_sentinel, Label::kNear);
484 if (FLAG_debug_code) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000485 __ cmp(ecx, 0);
danno@chromium.org59400602013-08-13 17:09:37 +0000486 __ Assert(equal, kExpected0AsASmiSentinel);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000487 }
488 __ mov(ecx, GlobalObjectOperand());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000489 __ mov(ecx, FieldOperand(ecx, GlobalObject::kNativeContextOffset));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000490 __ mov(ecx, ContextOperand(ecx, Context::CLOSURE_INDEX));
491 __ bind(&after_sentinel);
492
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000493 // Set up the fixed slots.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000494 __ mov(ContextOperand(eax, Context::CLOSURE_INDEX), ecx);
495 __ mov(ContextOperand(eax, Context::PREVIOUS_INDEX), esi);
496 __ mov(ContextOperand(eax, Context::EXTENSION_INDEX), ebx);
497
498 // Copy the global object from the previous context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000499 __ mov(ebx, ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX));
500 __ mov(ContextOperand(eax, Context::GLOBAL_OBJECT_INDEX), ebx);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000501
502 // Initialize the rest of the slots to the hole value.
503 if (slots_ == 1) {
504 __ mov(ContextOperand(eax, Context::MIN_CONTEXT_SLOTS),
505 factory->the_hole_value());
506 } else {
507 __ mov(ebx, factory->the_hole_value());
508 for (int i = 0; i < slots_; i++) {
509 __ mov(ContextOperand(eax, i + Context::MIN_CONTEXT_SLOTS), ebx);
510 }
511 }
512
513 // Return and remove the on-stack parameters.
514 __ mov(esi, eax);
515 __ ret(2 * kPointerSize);
516
517 // Need to collect. Call into runtime system.
518 __ bind(&gc);
519 __ TailCallRuntime(Runtime::kPushBlockContext, 2, 1);
520}
521
522
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000523void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
524 // We don't allow a GC during a store buffer overflow so there is no need to
525 // store the registers in any particular way, but we do have to store and
526 // restore them.
527 __ pushad();
528 if (save_doubles_ == kSaveFPRegs) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000529 CpuFeatureScope scope(masm, SSE2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000530 __ sub(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters));
531 for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
532 XMMRegister reg = XMMRegister::from_code(i);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000533 __ movsd(Operand(esp, i * kDoubleSize), reg);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000534 }
535 }
536 const int argument_count = 1;
537
538 AllowExternalCallThatCantCauseGC scope(masm);
539 __ PrepareCallCFunction(argument_count, ecx);
540 __ mov(Operand(esp, 0 * kPointerSize),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000541 Immediate(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000542 __ CallCFunction(
543 ExternalReference::store_buffer_overflow_function(masm->isolate()),
544 argument_count);
545 if (save_doubles_ == kSaveFPRegs) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000546 CpuFeatureScope scope(masm, SSE2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000547 for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
548 XMMRegister reg = XMMRegister::from_code(i);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000549 __ movsd(reg, Operand(esp, i * kDoubleSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000550 }
551 __ add(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters));
552 }
553 __ popad();
554 __ ret(0);
555}
556
557
ricow@chromium.org65fae842010-08-25 15:26:24 +0000558class FloatingPointHelper : public AllStatic {
559 public:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000560 enum ArgLocation {
561 ARGS_ON_STACK,
562 ARGS_IN_REGISTERS
563 };
564
565 // Code pattern for loading a floating point value. Input value must
566 // be either a smi or a heap number object (fp value). Requirements:
567 // operand in register number. Returns operand as floating point number
568 // on FPU stack.
569 static void LoadFloatOperand(MacroAssembler* masm, Register number);
570
ricow@chromium.org65fae842010-08-25 15:26:24 +0000571 // Test if operands are smi or number objects (fp). Requirements:
572 // operand_1 in eax, operand_2 in edx; falls through on float
573 // operands, jumps to the non_float label otherwise.
574 static void CheckFloatOperands(MacroAssembler* masm,
575 Label* non_float,
576 Register scratch);
577
ricow@chromium.org65fae842010-08-25 15:26:24 +0000578 // Test if operands are numbers (smi or HeapNumber objects), and load
579 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if
580 // either operand is not a number. Operands are in edx and eax.
581 // Leaves operands unchanged.
582 static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000583};
584
585
danno@chromium.org169691d2013-07-15 08:01:13 +0000586void DoubleToIStub::Generate(MacroAssembler* masm) {
587 Register input_reg = this->source();
588 Register final_result_reg = this->destination();
589 ASSERT(is_truncating());
590
591 Label check_negative, process_64_bits, done, done_no_stash;
592
593 int double_offset = offset();
594
595 // Account for return address and saved regs if input is esp.
596 if (input_reg.is(esp)) double_offset += 3 * kPointerSize;
597
598 MemOperand mantissa_operand(MemOperand(input_reg, double_offset));
599 MemOperand exponent_operand(MemOperand(input_reg,
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000600 double_offset + kDoubleSize / 2));
danno@chromium.org169691d2013-07-15 08:01:13 +0000601
602 Register scratch1;
603 {
604 Register scratch_candidates[3] = { ebx, edx, edi };
605 for (int i = 0; i < 3; i++) {
606 scratch1 = scratch_candidates[i];
607 if (!final_result_reg.is(scratch1) && !input_reg.is(scratch1)) break;
608 }
609 }
610 // Since we must use ecx for shifts below, use some other register (eax)
611 // to calculate the result if ecx is the requested return register.
612 Register result_reg = final_result_reg.is(ecx) ? eax : final_result_reg;
613 // Save ecx if it isn't the return register and therefore volatile, or if it
614 // is the return register, then save the temp register we use in its stead for
615 // the result.
616 Register save_reg = final_result_reg.is(ecx) ? eax : ecx;
617 __ push(scratch1);
618 __ push(save_reg);
619
620 bool stash_exponent_copy = !input_reg.is(esp);
621 __ mov(scratch1, mantissa_operand);
622 if (CpuFeatures::IsSupported(SSE3)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000623 CpuFeatureScope scope(masm, SSE3);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000624 // Load x87 register with heap number.
danno@chromium.org169691d2013-07-15 08:01:13 +0000625 __ fld_d(mantissa_operand);
626 }
627 __ mov(ecx, exponent_operand);
628 if (stash_exponent_copy) __ push(ecx);
629
630 __ and_(ecx, HeapNumber::kExponentMask);
631 __ shr(ecx, HeapNumber::kExponentShift);
632 __ lea(result_reg, MemOperand(ecx, -HeapNumber::kExponentBias));
633 __ cmp(result_reg, Immediate(HeapNumber::kMantissaBits));
634 __ j(below, &process_64_bits);
635
636 // Result is entirely in lower 32-bits of mantissa
637 int delta = HeapNumber::kExponentBias + Double::kPhysicalSignificandSize;
638 if (CpuFeatures::IsSupported(SSE3)) {
639 __ fstp(0);
640 }
641 __ sub(ecx, Immediate(delta));
642 __ xor_(result_reg, result_reg);
643 __ cmp(ecx, Immediate(31));
644 __ j(above, &done);
645 __ shl_cl(scratch1);
646 __ jmp(&check_negative);
647
648 __ bind(&process_64_bits);
649 if (CpuFeatures::IsSupported(SSE3)) {
650 CpuFeatureScope scope(masm, SSE3);
651 if (stash_exponent_copy) {
652 // Already a copy of the exponent on the stack, overwrite it.
653 STATIC_ASSERT(kDoubleSize == 2 * kPointerSize);
654 __ sub(esp, Immediate(kDoubleSize / 2));
655 } else {
656 // Reserve space for 64 bit answer.
657 __ sub(esp, Immediate(kDoubleSize)); // Nolint.
658 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000659 // Do conversion, which cannot fail because we checked the exponent.
660 __ fisttp_d(Operand(esp, 0));
danno@chromium.org169691d2013-07-15 08:01:13 +0000661 __ mov(result_reg, Operand(esp, 0)); // Load low word of answer as result
662 __ add(esp, Immediate(kDoubleSize));
663 __ jmp(&done_no_stash);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000664 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +0000665 // Result must be extracted from shifted 32-bit mantissa
666 __ sub(ecx, Immediate(delta));
667 __ neg(ecx);
668 if (stash_exponent_copy) {
669 __ mov(result_reg, MemOperand(esp, 0));
670 } else {
671 __ mov(result_reg, exponent_operand);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000672 }
danno@chromium.org169691d2013-07-15 08:01:13 +0000673 __ and_(result_reg,
674 Immediate(static_cast<uint32_t>(Double::kSignificandMask >> 32)));
675 __ add(result_reg,
676 Immediate(static_cast<uint32_t>(Double::kHiddenBit >> 32)));
677 __ shrd(result_reg, scratch1);
678 __ shr_cl(result_reg);
679 __ test(ecx, Immediate(32));
680 if (CpuFeatures::IsSupported(CMOV)) {
681 CpuFeatureScope use_cmov(masm, CMOV);
682 __ cmov(not_equal, scratch1, result_reg);
683 } else {
684 Label skip_mov;
685 __ j(equal, &skip_mov, Label::kNear);
686 __ mov(scratch1, result_reg);
687 __ bind(&skip_mov);
688 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000689 }
danno@chromium.org169691d2013-07-15 08:01:13 +0000690
691 // If the double was negative, negate the integer result.
692 __ bind(&check_negative);
693 __ mov(result_reg, scratch1);
694 __ neg(result_reg);
695 if (stash_exponent_copy) {
696 __ cmp(MemOperand(esp, 0), Immediate(0));
697 } else {
698 __ cmp(exponent_operand, Immediate(0));
699 }
700 if (CpuFeatures::IsSupported(CMOV)) {
701 CpuFeatureScope use_cmov(masm, CMOV);
702 __ cmov(greater, result_reg, scratch1);
703 } else {
704 Label skip_mov;
705 __ j(less_equal, &skip_mov, Label::kNear);
706 __ mov(result_reg, scratch1);
707 __ bind(&skip_mov);
708 }
709
710 // Restore registers
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000711 __ bind(&done);
danno@chromium.org169691d2013-07-15 08:01:13 +0000712 if (stash_exponent_copy) {
713 __ add(esp, Immediate(kDoubleSize / 2));
714 }
715 __ bind(&done_no_stash);
716 if (!final_result_reg.is(result_reg)) {
717 ASSERT(final_result_reg.is(ecx));
718 __ mov(final_result_reg, result_reg);
719 }
720 __ pop(save_reg);
721 __ pop(scratch1);
722 __ ret(0);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000723}
724
725
ricow@chromium.org65fae842010-08-25 15:26:24 +0000726void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
727 Register number) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000728 Label load_smi, done;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000729
whesse@chromium.org7b260152011-06-20 15:33:18 +0000730 __ JumpIfSmi(number, &load_smi, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000731 __ fld_d(FieldOperand(number, HeapNumber::kValueOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000732 __ jmp(&done, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000733
734 __ bind(&load_smi);
735 __ SmiUntag(number);
736 __ push(number);
737 __ fild_s(Operand(esp, 0));
738 __ pop(number);
739
740 __ bind(&done);
741}
742
743
ricow@chromium.org65fae842010-08-25 15:26:24 +0000744void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm,
745 Label* not_numbers) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000746 Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000747 // Load operand in edx into xmm0, or branch to not_numbers.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000748 __ JumpIfSmi(edx, &load_smi_edx, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000749 Factory* factory = masm->isolate()->factory();
750 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000751 __ j(not_equal, not_numbers); // Argument in edx is not a number.
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000752 __ movsd(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000753 __ bind(&load_eax);
754 // Load operand in eax into xmm1, or branch to not_numbers.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000755 __ JumpIfSmi(eax, &load_smi_eax, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000756 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map());
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000757 __ j(equal, &load_float_eax, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000758 __ jmp(not_numbers); // Argument in eax is not a number.
759 __ bind(&load_smi_edx);
760 __ SmiUntag(edx); // Untag smi before converting to float.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000761 __ Cvtsi2sd(xmm0, edx);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000762 __ SmiTag(edx); // Retag smi for heap number overwriting test.
763 __ jmp(&load_eax);
764 __ bind(&load_smi_eax);
765 __ SmiUntag(eax); // Untag smi before converting to float.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000766 __ Cvtsi2sd(xmm1, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000767 __ SmiTag(eax); // Retag smi for heap number overwriting test.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000768 __ jmp(&done, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000769 __ bind(&load_float_eax);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000770 __ movsd(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000771 __ bind(&done);
772}
773
774
ricow@chromium.org65fae842010-08-25 15:26:24 +0000775void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm,
776 Label* non_float,
777 Register scratch) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000778 Label test_other, done;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000779 // Test if both operands are floats or smi -> scratch=k_is_float;
780 // Otherwise scratch = k_not_float.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000781 __ JumpIfSmi(edx, &test_other, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000782 __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000783 Factory* factory = masm->isolate()->factory();
784 __ cmp(scratch, factory->heap_number_map());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000785 __ j(not_equal, non_float); // argument in edx is not a number -> NaN
786
787 __ bind(&test_other);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000788 __ JumpIfSmi(eax, &done, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000789 __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000790 __ cmp(scratch, factory->heap_number_map());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000791 __ j(not_equal, non_float); // argument in eax is not a number -> NaN
792
793 // Fall-through: Both operands are numbers.
794 __ bind(&done);
795}
796
797
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000798void MathPowStub::Generate(MacroAssembler* masm) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000799 CpuFeatureScope use_sse2(masm, SSE2);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000800 Factory* factory = masm->isolate()->factory();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000801 const Register exponent = eax;
802 const Register base = edx;
803 const Register scratch = ecx;
804 const XMMRegister double_result = xmm3;
805 const XMMRegister double_base = xmm2;
806 const XMMRegister double_exponent = xmm1;
807 const XMMRegister double_scratch = xmm4;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000808
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000809 Label call_runtime, done, exponent_not_smi, int_exponent;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000810
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000811 // Save 1 in double_result - we need this several times later on.
812 __ mov(scratch, Immediate(1));
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000813 __ Cvtsi2sd(double_result, scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000814
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000815 if (exponent_type_ == ON_STACK) {
816 Label base_is_smi, unpack_exponent;
817 // The exponent and base are supplied as arguments on the stack.
818 // This can only happen if the stub is called from non-optimized code.
819 // Load input parameters from stack.
820 __ mov(base, Operand(esp, 2 * kPointerSize));
821 __ mov(exponent, Operand(esp, 1 * kPointerSize));
822
823 __ JumpIfSmi(base, &base_is_smi, Label::kNear);
824 __ cmp(FieldOperand(base, HeapObject::kMapOffset),
825 factory->heap_number_map());
826 __ j(not_equal, &call_runtime);
827
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000828 __ movsd(double_base, FieldOperand(base, HeapNumber::kValueOffset));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000829 __ jmp(&unpack_exponent, Label::kNear);
830
831 __ bind(&base_is_smi);
832 __ SmiUntag(base);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000833 __ Cvtsi2sd(double_base, base);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000834
835 __ bind(&unpack_exponent);
836 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
837 __ SmiUntag(exponent);
838 __ jmp(&int_exponent);
839
840 __ bind(&exponent_not_smi);
841 __ cmp(FieldOperand(exponent, HeapObject::kMapOffset),
842 factory->heap_number_map());
843 __ j(not_equal, &call_runtime);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000844 __ movsd(double_exponent,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000845 FieldOperand(exponent, HeapNumber::kValueOffset));
846 } else if (exponent_type_ == TAGGED) {
847 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
848 __ SmiUntag(exponent);
849 __ jmp(&int_exponent);
850
851 __ bind(&exponent_not_smi);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000852 __ movsd(double_exponent,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000853 FieldOperand(exponent, HeapNumber::kValueOffset));
854 }
855
856 if (exponent_type_ != INTEGER) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000857 Label fast_power, try_arithmetic_simplification;
858 __ DoubleToI(exponent, double_exponent, double_scratch,
859 TREAT_MINUS_ZERO_AS_ZERO, &try_arithmetic_simplification);
860 __ jmp(&int_exponent);
861
862 __ bind(&try_arithmetic_simplification);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000863 // Skip to runtime if possibly NaN (indicated by the indefinite integer).
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000864 __ cvttsd2si(exponent, Operand(double_exponent));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000865 __ cmp(exponent, Immediate(0x80000000u));
866 __ j(equal, &call_runtime);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000867
868 if (exponent_type_ == ON_STACK) {
869 // Detect square root case. Crankshaft detects constant +/-0.5 at
870 // compile time and uses DoMathPowHalf instead. We then skip this check
871 // for non-constant cases of +/-0.5 as these hardly occur.
872 Label continue_sqrt, continue_rsqrt, not_plus_half;
873 // Test for 0.5.
874 // Load double_scratch with 0.5.
875 __ mov(scratch, Immediate(0x3F000000u));
876 __ movd(double_scratch, scratch);
877 __ cvtss2sd(double_scratch, double_scratch);
878 // Already ruled out NaNs for exponent.
879 __ ucomisd(double_scratch, double_exponent);
880 __ j(not_equal, &not_plus_half, Label::kNear);
881
882 // Calculates square root of base. Check for the special case of
883 // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
884 // According to IEEE-754, single-precision -Infinity has the highest
885 // 9 bits set and the lowest 23 bits cleared.
886 __ mov(scratch, 0xFF800000u);
887 __ movd(double_scratch, scratch);
888 __ cvtss2sd(double_scratch, double_scratch);
889 __ ucomisd(double_base, double_scratch);
890 // Comparing -Infinity with NaN results in "unordered", which sets the
891 // zero flag as if both were equal. However, it also sets the carry flag.
892 __ j(not_equal, &continue_sqrt, Label::kNear);
893 __ j(carry, &continue_sqrt, Label::kNear);
894
895 // Set result to Infinity in the special case.
896 __ xorps(double_result, double_result);
897 __ subsd(double_result, double_scratch);
898 __ jmp(&done);
899
900 __ bind(&continue_sqrt);
901 // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
902 __ xorps(double_scratch, double_scratch);
903 __ addsd(double_scratch, double_base); // Convert -0 to +0.
904 __ sqrtsd(double_result, double_scratch);
905 __ jmp(&done);
906
907 // Test for -0.5.
908 __ bind(&not_plus_half);
909 // Load double_exponent with -0.5 by substracting 1.
910 __ subsd(double_scratch, double_result);
911 // Already ruled out NaNs for exponent.
912 __ ucomisd(double_scratch, double_exponent);
913 __ j(not_equal, &fast_power, Label::kNear);
914
915 // Calculates reciprocal of square root of base. Check for the special
916 // case of Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
917 // According to IEEE-754, single-precision -Infinity has the highest
918 // 9 bits set and the lowest 23 bits cleared.
919 __ mov(scratch, 0xFF800000u);
920 __ movd(double_scratch, scratch);
921 __ cvtss2sd(double_scratch, double_scratch);
922 __ ucomisd(double_base, double_scratch);
923 // Comparing -Infinity with NaN results in "unordered", which sets the
924 // zero flag as if both were equal. However, it also sets the carry flag.
925 __ j(not_equal, &continue_rsqrt, Label::kNear);
926 __ j(carry, &continue_rsqrt, Label::kNear);
927
928 // Set result to 0 in the special case.
929 __ xorps(double_result, double_result);
930 __ jmp(&done);
931
932 __ bind(&continue_rsqrt);
933 // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
934 __ xorps(double_exponent, double_exponent);
935 __ addsd(double_exponent, double_base); // Convert -0 to +0.
936 __ sqrtsd(double_exponent, double_exponent);
937 __ divsd(double_result, double_exponent);
938 __ jmp(&done);
939 }
940
941 // Using FPU instructions to calculate power.
942 Label fast_power_failed;
943 __ bind(&fast_power);
944 __ fnclex(); // Clear flags to catch exceptions later.
945 // Transfer (B)ase and (E)xponent onto the FPU register stack.
946 __ sub(esp, Immediate(kDoubleSize));
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000947 __ movsd(Operand(esp, 0), double_exponent);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000948 __ fld_d(Operand(esp, 0)); // E
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000949 __ movsd(Operand(esp, 0), double_base);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000950 __ fld_d(Operand(esp, 0)); // B, E
951
952 // Exponent is in st(1) and base is in st(0)
953 // B ^ E = (2^(E * log2(B)) - 1) + 1 = (2^X - 1) + 1 for X = E * log2(B)
954 // FYL2X calculates st(1) * log2(st(0))
955 __ fyl2x(); // X
956 __ fld(0); // X, X
957 __ frndint(); // rnd(X), X
958 __ fsub(1); // rnd(X), X-rnd(X)
959 __ fxch(1); // X - rnd(X), rnd(X)
960 // F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1
961 __ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X)
962 __ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X)
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000963 __ faddp(1); // 2^(X-rnd(X)), rnd(X)
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000964 // FSCALE calculates st(0) * 2^st(1)
965 __ fscale(); // 2^X, rnd(X)
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000966 __ fstp(1); // 2^X
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000967 // Bail out to runtime in case of exceptions in the status word.
968 __ fnstsw_ax();
969 __ test_b(eax, 0x5F); // We check for all but precision exception.
970 __ j(not_zero, &fast_power_failed, Label::kNear);
971 __ fstp_d(Operand(esp, 0));
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000972 __ movsd(double_result, Operand(esp, 0));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000973 __ add(esp, Immediate(kDoubleSize));
974 __ jmp(&done);
975
976 __ bind(&fast_power_failed);
977 __ fninit();
978 __ add(esp, Immediate(kDoubleSize));
979 __ jmp(&call_runtime);
980 }
981
982 // Calculate power with integer exponent.
983 __ bind(&int_exponent);
984 const XMMRegister double_scratch2 = double_exponent;
985 __ mov(scratch, exponent); // Back up exponent.
986 __ movsd(double_scratch, double_base); // Back up base.
987 __ movsd(double_scratch2, double_result); // Load double_exponent with 1.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000988
989 // Get absolute value of exponent.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000990 Label no_neg, while_true, while_false;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000991 __ test(scratch, scratch);
992 __ j(positive, &no_neg, Label::kNear);
993 __ neg(scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000994 __ bind(&no_neg);
995
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000996 __ j(zero, &while_false, Label::kNear);
997 __ shr(scratch, 1);
998 // Above condition means CF==0 && ZF==0. This means that the
999 // bit that has been shifted out is 0 and the result is not 0.
1000 __ j(above, &while_true, Label::kNear);
1001 __ movsd(double_result, double_scratch);
1002 __ j(zero, &while_false, Label::kNear);
1003
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001004 __ bind(&while_true);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001005 __ shr(scratch, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001006 __ mulsd(double_scratch, double_scratch);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001007 __ j(above, &while_true, Label::kNear);
1008 __ mulsd(double_result, double_scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001009 __ j(not_zero, &while_true);
1010
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001011 __ bind(&while_false);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001012 // scratch has the original value of the exponent - if the exponent is
1013 // negative, return 1/result.
1014 __ test(exponent, exponent);
1015 __ j(positive, &done);
1016 __ divsd(double_scratch2, double_result);
1017 __ movsd(double_result, double_scratch2);
1018 // Test whether result is zero. Bail out to check for subnormal result.
1019 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
1020 __ xorps(double_scratch2, double_scratch2);
1021 __ ucomisd(double_scratch2, double_result); // Result cannot be NaN.
1022 // double_exponent aliased as double_scratch2 has already been overwritten
1023 // and may not have contained the exponent value in the first place when the
1024 // exponent is a smi. We reset it with exponent value before bailing out.
1025 __ j(not_equal, &done);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001026 __ Cvtsi2sd(double_exponent, exponent);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001027
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001028 // Returning or bailing out.
1029 Counters* counters = masm->isolate()->counters();
1030 if (exponent_type_ == ON_STACK) {
1031 // The arguments are still on the stack.
1032 __ bind(&call_runtime);
1033 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001034
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001035 // The stub is called from non-optimized code, which expects the result
1036 // as heap number in exponent.
1037 __ bind(&done);
1038 __ AllocateHeapNumber(eax, scratch, base, &call_runtime);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00001039 __ movsd(FieldOperand(eax, HeapNumber::kValueOffset), double_result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001040 __ IncrementCounter(counters->math_pow(), 1);
1041 __ ret(2 * kPointerSize);
1042 } else {
1043 __ bind(&call_runtime);
1044 {
1045 AllowExternalCallThatCantCauseGC scope(masm);
1046 __ PrepareCallCFunction(4, scratch);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00001047 __ movsd(Operand(esp, 0 * kDoubleSize), double_base);
1048 __ movsd(Operand(esp, 1 * kDoubleSize), double_exponent);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001049 __ CallCFunction(
1050 ExternalReference::power_double_double_function(masm->isolate()), 4);
1051 }
1052 // Return value is in st(0) on ia32.
1053 // Store it into the (fixed) result register.
1054 __ sub(esp, Immediate(kDoubleSize));
1055 __ fstp_d(Operand(esp, 0));
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00001056 __ movsd(double_result, Operand(esp, 0));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001057 __ add(esp, Immediate(kDoubleSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001058
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001059 __ bind(&done);
1060 __ IncrementCounter(counters->math_pow(), 1);
1061 __ ret(0);
1062 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001063}
1064
1065
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001066void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
1067 // ----------- S t a t e -------------
1068 // -- ecx : name
1069 // -- edx : receiver
1070 // -- esp[0] : return address
1071 // -----------------------------------
1072 Label miss;
1073
1074 if (kind() == Code::KEYED_LOAD_IC) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001075 __ cmp(ecx, Immediate(masm->isolate()->factory()->prototype_string()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001076 __ j(not_equal, &miss);
1077 }
1078
1079 StubCompiler::GenerateLoadFunctionPrototype(masm, edx, eax, ebx, &miss);
1080 __ bind(&miss);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001081 StubCompiler::TailCallBuiltin(
1082 masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001083}
1084
1085
1086void StringLengthStub::Generate(MacroAssembler* masm) {
1087 // ----------- S t a t e -------------
1088 // -- ecx : name
1089 // -- edx : receiver
1090 // -- esp[0] : return address
1091 // -----------------------------------
1092 Label miss;
1093
1094 if (kind() == Code::KEYED_LOAD_IC) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001095 __ cmp(ecx, Immediate(masm->isolate()->factory()->length_string()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001096 __ j(not_equal, &miss);
1097 }
1098
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001099 StubCompiler::GenerateLoadStringLength(masm, edx, eax, ebx, &miss);
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001100 __ bind(&miss);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001101 StubCompiler::TailCallBuiltin(
1102 masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001103}
1104
1105
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001106void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
1107 // ----------- S t a t e -------------
1108 // -- eax : value
1109 // -- ecx : name
1110 // -- edx : receiver
1111 // -- esp[0] : return address
1112 // -----------------------------------
1113 //
1114 // This accepts as a receiver anything JSArray::SetElementsLength accepts
1115 // (currently anything except for external arrays which means anything with
1116 // elements of FixedArray type). Value must be a number, but only smis are
1117 // accepted as the most common case.
1118
1119 Label miss;
1120
1121 Register receiver = edx;
1122 Register value = eax;
1123 Register scratch = ebx;
1124
ulan@chromium.org750145a2013-03-07 15:14:13 +00001125 if (kind() == Code::KEYED_STORE_IC) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001126 __ cmp(ecx, Immediate(masm->isolate()->factory()->length_string()));
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001127 __ j(not_equal, &miss);
1128 }
1129
1130 // Check that the receiver isn't a smi.
1131 __ JumpIfSmi(receiver, &miss);
1132
1133 // Check that the object is a JS array.
1134 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
1135 __ j(not_equal, &miss);
1136
1137 // Check that elements are FixedArray.
1138 // We rely on StoreIC_ArrayLength below to deal with all types of
1139 // fast elements (including COW).
1140 __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
1141 __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
1142 __ j(not_equal, &miss);
1143
1144 // Check that the array has fast properties, otherwise the length
1145 // property might have been redefined.
1146 __ mov(scratch, FieldOperand(receiver, JSArray::kPropertiesOffset));
1147 __ CompareRoot(FieldOperand(scratch, FixedArray::kMapOffset),
1148 Heap::kHashTableMapRootIndex);
1149 __ j(equal, &miss);
1150
1151 // Check that value is a smi.
1152 __ JumpIfNotSmi(value, &miss);
1153
1154 // Prepare tail call to StoreIC_ArrayLength.
1155 __ pop(scratch);
1156 __ push(receiver);
1157 __ push(value);
1158 __ push(scratch); // return address
1159
1160 ExternalReference ref =
1161 ExternalReference(IC_Utility(IC::kStoreIC_ArrayLength), masm->isolate());
1162 __ TailCallExternalReference(ref, 2, 1);
1163
1164 __ bind(&miss);
1165
danno@chromium.orgbee51992013-07-10 14:57:15 +00001166 StubCompiler::TailCallBuiltin(
1167 masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001168}
1169
1170
ricow@chromium.org65fae842010-08-25 15:26:24 +00001171void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
1172 // The key is in edx and the parameter count is in eax.
1173
1174 // The displacement is used for skipping the frame pointer on the
1175 // stack. It is the offset of the last parameter (if any) relative
1176 // to the frame pointer.
1177 static const int kDisplacement = 1 * kPointerSize;
1178
1179 // Check that the key is a smi.
1180 Label slow;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001181 __ JumpIfNotSmi(edx, &slow, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001182
1183 // Check if the calling frame is an arguments adaptor frame.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001184 Label adaptor;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001185 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1186 __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001187 __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001188 __ j(equal, &adaptor, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001189
1190 // Check index against formal parameters count limit passed in
1191 // through register eax. Use unsigned comparison to get negative
1192 // check for free.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001193 __ cmp(edx, eax);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001194 __ j(above_equal, &slow, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001195
1196 // Read the argument from the stack and return it.
1197 STATIC_ASSERT(kSmiTagSize == 1);
1198 STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these.
1199 __ lea(ebx, Operand(ebp, eax, times_2, 0));
1200 __ neg(edx);
1201 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
1202 __ ret(0);
1203
1204 // Arguments adaptor case: Check index against actual arguments
1205 // limit found in the arguments adaptor frame. Use unsigned
1206 // comparison to get negative check for free.
1207 __ bind(&adaptor);
1208 __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001209 __ cmp(edx, ecx);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001210 __ j(above_equal, &slow, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001211
1212 // Read the argument from the stack and return it.
1213 STATIC_ASSERT(kSmiTagSize == 1);
1214 STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these.
1215 __ lea(ebx, Operand(ebx, ecx, times_2, 0));
1216 __ neg(edx);
1217 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
1218 __ ret(0);
1219
1220 // Slow-case: Handle non-smi or out-of-bounds access to arguments
1221 // by calling the runtime system.
1222 __ bind(&slow);
1223 __ pop(ebx); // Return address.
1224 __ push(edx);
1225 __ push(ebx);
1226 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
1227}
1228
1229
whesse@chromium.org7b260152011-06-20 15:33:18 +00001230void ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001231 // esp[0] : return address
1232 // esp[4] : number of parameters
1233 // esp[8] : receiver displacement
whesse@chromium.org7b260152011-06-20 15:33:18 +00001234 // esp[12] : function
ricow@chromium.org65fae842010-08-25 15:26:24 +00001235
whesse@chromium.org7b260152011-06-20 15:33:18 +00001236 // Check if the calling frame is an arguments adaptor frame.
1237 Label runtime;
1238 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1239 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001240 __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001241 __ j(not_equal, &runtime, Label::kNear);
1242
1243 // Patch the arguments.length and the parameters pointer.
1244 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
1245 __ mov(Operand(esp, 1 * kPointerSize), ecx);
1246 __ lea(edx, Operand(edx, ecx, times_2,
1247 StandardFrameConstants::kCallerSPOffset));
1248 __ mov(Operand(esp, 2 * kPointerSize), edx);
1249
1250 __ bind(&runtime);
1251 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
1252}
1253
1254
1255void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001256 Isolate* isolate = masm->isolate();
1257
whesse@chromium.org7b260152011-06-20 15:33:18 +00001258 // esp[0] : return address
1259 // esp[4] : number of parameters (tagged)
1260 // esp[8] : receiver displacement
1261 // esp[12] : function
1262
1263 // ebx = parameter count (tagged)
1264 __ mov(ebx, Operand(esp, 1 * kPointerSize));
1265
1266 // Check if the calling frame is an arguments adaptor frame.
1267 // TODO(rossberg): Factor out some of the bits that are shared with the other
1268 // Generate* functions.
1269 Label runtime;
1270 Label adaptor_frame, try_allocate;
1271 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1272 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001273 __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001274 __ j(equal, &adaptor_frame, Label::kNear);
1275
1276 // No adaptor, parameter count = argument count.
1277 __ mov(ecx, ebx);
1278 __ jmp(&try_allocate, Label::kNear);
1279
1280 // We have an adaptor frame. Patch the parameters pointer.
1281 __ bind(&adaptor_frame);
1282 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
1283 __ lea(edx, Operand(edx, ecx, times_2,
1284 StandardFrameConstants::kCallerSPOffset));
1285 __ mov(Operand(esp, 2 * kPointerSize), edx);
1286
1287 // ebx = parameter count (tagged)
1288 // ecx = argument count (tagged)
1289 // esp[4] = parameter count (tagged)
1290 // esp[8] = address of receiver argument
1291 // Compute the mapped parameter count = min(ebx, ecx) in ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001292 __ cmp(ebx, ecx);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001293 __ j(less_equal, &try_allocate, Label::kNear);
1294 __ mov(ebx, ecx);
1295
1296 __ bind(&try_allocate);
1297
1298 // Save mapped parameter count.
1299 __ push(ebx);
1300
1301 // Compute the sizes of backing store, parameter map, and arguments object.
1302 // 1. Parameter map, has 2 extra words containing context and backing store.
1303 const int kParameterMapHeaderSize =
1304 FixedArray::kHeaderSize + 2 * kPointerSize;
1305 Label no_parameter_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001306 __ test(ebx, ebx);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001307 __ j(zero, &no_parameter_map, Label::kNear);
1308 __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize));
1309 __ bind(&no_parameter_map);
1310
1311 // 2. Backing store.
1312 __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize));
1313
1314 // 3. Arguments object.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001315 __ add(ebx, Immediate(Heap::kArgumentsObjectSize));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001316
1317 // Do the allocation of all three objects in one go.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001318 __ Allocate(ebx, eax, edx, edi, &runtime, TAG_OBJECT);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001319
1320 // eax = address of new object(s) (tagged)
1321 // ecx = argument count (tagged)
1322 // esp[0] = mapped parameter count (tagged)
1323 // esp[8] = parameter count (tagged)
1324 // esp[12] = address of receiver argument
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001325 // Get the arguments boilerplate from the current native context into edi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001326 Label has_mapped_parameters, copy;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001327 __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
1328 __ mov(edi, FieldOperand(edi, GlobalObject::kNativeContextOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001329 __ mov(ebx, Operand(esp, 0 * kPointerSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001330 __ test(ebx, ebx);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001331 __ j(not_zero, &has_mapped_parameters, Label::kNear);
1332 __ mov(edi, Operand(edi,
1333 Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX)));
1334 __ jmp(&copy, Label::kNear);
1335
1336 __ bind(&has_mapped_parameters);
1337 __ mov(edi, Operand(edi,
1338 Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX)));
1339 __ bind(&copy);
1340
1341 // eax = address of new object (tagged)
1342 // ebx = mapped parameter count (tagged)
1343 // ecx = argument count (tagged)
1344 // edi = address of boilerplate object (tagged)
1345 // esp[0] = mapped parameter count (tagged)
1346 // esp[8] = parameter count (tagged)
1347 // esp[12] = address of receiver argument
1348 // Copy the JS object part.
1349 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
1350 __ mov(edx, FieldOperand(edi, i));
1351 __ mov(FieldOperand(eax, i), edx);
1352 }
1353
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001354 // Set up the callee in-object property.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001355 STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
1356 __ mov(edx, Operand(esp, 4 * kPointerSize));
1357 __ mov(FieldOperand(eax, JSObject::kHeaderSize +
1358 Heap::kArgumentsCalleeIndex * kPointerSize),
1359 edx);
1360
1361 // Use the length (smi tagged) and set that as an in-object property too.
1362 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
1363 __ mov(FieldOperand(eax, JSObject::kHeaderSize +
1364 Heap::kArgumentsLengthIndex * kPointerSize),
1365 ecx);
1366
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001367 // Set up the elements pointer in the allocated arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001368 // If we allocated a parameter map, edi will point there, otherwise to the
1369 // backing store.
1370 __ lea(edi, Operand(eax, Heap::kArgumentsObjectSize));
1371 __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
1372
1373 // eax = address of new object (tagged)
1374 // ebx = mapped parameter count (tagged)
1375 // ecx = argument count (tagged)
1376 // edi = address of parameter map or backing store (tagged)
1377 // esp[0] = mapped parameter count (tagged)
1378 // esp[8] = parameter count (tagged)
1379 // esp[12] = address of receiver argument
1380 // Free a register.
1381 __ push(eax);
1382
1383 // Initialize parameter map. If there are no mapped arguments, we're done.
1384 Label skip_parameter_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001385 __ test(ebx, ebx);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001386 __ j(zero, &skip_parameter_map);
1387
1388 __ mov(FieldOperand(edi, FixedArray::kMapOffset),
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001389 Immediate(isolate->factory()->non_strict_arguments_elements_map()));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001390 __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2))));
1391 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax);
1392 __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi);
1393 __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize));
1394 __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax);
1395
1396 // Copy the parameter slots and the holes in the arguments.
1397 // We need to fill in mapped_parameter_count slots. They index the context,
1398 // where parameters are stored in reverse order, at
1399 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1
1400 // The mapped parameter thus need to get indices
1401 // MIN_CONTEXT_SLOTS+parameter_count-1 ..
1402 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count
1403 // We loop from right to left.
1404 Label parameters_loop, parameters_test;
1405 __ push(ecx);
1406 __ mov(eax, Operand(esp, 2 * kPointerSize));
1407 __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS)));
1408 __ add(ebx, Operand(esp, 4 * kPointerSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001409 __ sub(ebx, eax);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001410 __ mov(ecx, isolate->factory()->the_hole_value());
whesse@chromium.org7b260152011-06-20 15:33:18 +00001411 __ mov(edx, edi);
1412 __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize));
1413 // eax = loop variable (tagged)
1414 // ebx = mapping index (tagged)
1415 // ecx = the hole value
1416 // edx = address of parameter map (tagged)
1417 // edi = address of backing store (tagged)
1418 // esp[0] = argument count (tagged)
1419 // esp[4] = address of new object (tagged)
1420 // esp[8] = mapped parameter count (tagged)
1421 // esp[16] = parameter count (tagged)
1422 // esp[20] = address of receiver argument
1423 __ jmp(&parameters_test, Label::kNear);
1424
1425 __ bind(&parameters_loop);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001426 __ sub(eax, Immediate(Smi::FromInt(1)));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001427 __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx);
1428 __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001429 __ add(ebx, Immediate(Smi::FromInt(1)));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001430 __ bind(&parameters_test);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001431 __ test(eax, eax);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001432 __ j(not_zero, &parameters_loop, Label::kNear);
1433 __ pop(ecx);
1434
1435 __ bind(&skip_parameter_map);
1436
1437 // ecx = argument count (tagged)
1438 // edi = address of backing store (tagged)
1439 // esp[0] = address of new object (tagged)
1440 // esp[4] = mapped parameter count (tagged)
1441 // esp[12] = parameter count (tagged)
1442 // esp[16] = address of receiver argument
1443 // Copy arguments header and remaining slots (if there are any).
1444 __ mov(FieldOperand(edi, FixedArray::kMapOffset),
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001445 Immediate(isolate->factory()->fixed_array_map()));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001446 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
1447
1448 Label arguments_loop, arguments_test;
1449 __ mov(ebx, Operand(esp, 1 * kPointerSize));
1450 __ mov(edx, Operand(esp, 4 * kPointerSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001451 __ sub(edx, ebx); // Is there a smarter way to do negative scaling?
1452 __ sub(edx, ebx);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001453 __ jmp(&arguments_test, Label::kNear);
1454
1455 __ bind(&arguments_loop);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001456 __ sub(edx, Immediate(kPointerSize));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001457 __ mov(eax, Operand(edx, 0));
1458 __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001459 __ add(ebx, Immediate(Smi::FromInt(1)));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001460
1461 __ bind(&arguments_test);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001462 __ cmp(ebx, ecx);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001463 __ j(less, &arguments_loop, Label::kNear);
1464
1465 // Restore.
1466 __ pop(eax); // Address of arguments object.
1467 __ pop(ebx); // Parameter count.
1468
1469 // Return and remove the on-stack parameters.
1470 __ ret(3 * kPointerSize);
1471
1472 // Do the runtime call to allocate the arguments object.
1473 __ bind(&runtime);
1474 __ pop(eax); // Remove saved parameter count.
1475 __ mov(Operand(esp, 1 * kPointerSize), ecx); // Patch argument count.
danno@chromium.org72204d52012-10-31 10:02:10 +00001476 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001477}
1478
1479
1480void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001481 Isolate* isolate = masm->isolate();
1482
whesse@chromium.org7b260152011-06-20 15:33:18 +00001483 // esp[0] : return address
1484 // esp[4] : number of parameters
1485 // esp[8] : receiver displacement
1486 // esp[12] : function
ricow@chromium.org65fae842010-08-25 15:26:24 +00001487
1488 // Check if the calling frame is an arguments adaptor frame.
1489 Label adaptor_frame, try_allocate, runtime;
1490 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1491 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001492 __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001493 __ j(equal, &adaptor_frame, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001494
1495 // Get the length from the frame.
1496 __ mov(ecx, Operand(esp, 1 * kPointerSize));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001497 __ jmp(&try_allocate, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001498
1499 // Patch the arguments.length and the parameters pointer.
1500 __ bind(&adaptor_frame);
1501 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
1502 __ mov(Operand(esp, 1 * kPointerSize), ecx);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001503 __ lea(edx, Operand(edx, ecx, times_2,
1504 StandardFrameConstants::kCallerSPOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001505 __ mov(Operand(esp, 2 * kPointerSize), edx);
1506
1507 // Try the new space allocation. Start out with computing the size of
1508 // the arguments object and the elements array.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001509 Label add_arguments_object;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001510 __ bind(&try_allocate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001511 __ test(ecx, ecx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001512 __ j(zero, &add_arguments_object, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001513 __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize));
1514 __ bind(&add_arguments_object);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001515 __ add(ecx, Immediate(Heap::kArgumentsObjectSizeStrict));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001516
1517 // Do the allocation of both objects in one go.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001518 __ Allocate(ecx, eax, edx, ebx, &runtime, TAG_OBJECT);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001519
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001520 // Get the arguments boilerplate from the current native context.
1521 __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
1522 __ mov(edi, FieldOperand(edi, GlobalObject::kNativeContextOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001523 const int offset =
1524 Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX);
1525 __ mov(edi, Operand(edi, offset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001526
1527 // Copy the JS object part.
1528 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
1529 __ mov(ebx, FieldOperand(edi, i));
1530 __ mov(FieldOperand(eax, i), ebx);
1531 }
1532
ricow@chromium.org65fae842010-08-25 15:26:24 +00001533 // Get the length (smi tagged) and set that as an in-object property too.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001534 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001535 __ mov(ecx, Operand(esp, 1 * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001536 __ mov(FieldOperand(eax, JSObject::kHeaderSize +
whesse@chromium.org7b260152011-06-20 15:33:18 +00001537 Heap::kArgumentsLengthIndex * kPointerSize),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001538 ecx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001539
1540 // If there are no actual arguments, we're done.
1541 Label done;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001542 __ test(ecx, ecx);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001543 __ j(zero, &done, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001544
1545 // Get the parameters pointer from the stack.
1546 __ mov(edx, Operand(esp, 2 * kPointerSize));
1547
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001548 // Set up the elements pointer in the allocated arguments object and
ricow@chromium.org65fae842010-08-25 15:26:24 +00001549 // initialize the header in the elements fixed array.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001550 __ lea(edi, Operand(eax, Heap::kArgumentsObjectSizeStrict));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001551 __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
1552 __ mov(FieldOperand(edi, FixedArray::kMapOffset),
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001553 Immediate(isolate->factory()->fixed_array_map()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001554
ricow@chromium.org65fae842010-08-25 15:26:24 +00001555 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
1556 // Untag the length for the loop below.
1557 __ SmiUntag(ecx);
1558
1559 // Copy the fixed array slots.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001560 Label loop;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001561 __ bind(&loop);
1562 __ mov(ebx, Operand(edx, -1 * kPointerSize)); // Skip receiver.
1563 __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001564 __ add(edi, Immediate(kPointerSize));
1565 __ sub(edx, Immediate(kPointerSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001566 __ dec(ecx);
1567 __ j(not_zero, &loop);
1568
1569 // Return and remove the on-stack parameters.
1570 __ bind(&done);
1571 __ ret(3 * kPointerSize);
1572
1573 // Do the runtime call to allocate the arguments object.
1574 __ bind(&runtime);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001575 __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001576}
1577
1578
1579void RegExpExecStub::Generate(MacroAssembler* masm) {
1580 // Just jump directly to runtime if native RegExp is not selected at compile
1581 // time or if regexp entry in generated code is turned off runtime switch or
1582 // at compilation.
1583#ifdef V8_INTERPRETED_REGEXP
1584 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
1585#else // V8_INTERPRETED_REGEXP
ricow@chromium.org65fae842010-08-25 15:26:24 +00001586
1587 // Stack frame on entry.
1588 // esp[0]: return address
1589 // esp[4]: last_match_info (expected JSArray)
1590 // esp[8]: previous index
1591 // esp[12]: subject string
1592 // esp[16]: JSRegExp object
1593
1594 static const int kLastMatchInfoOffset = 1 * kPointerSize;
1595 static const int kPreviousIndexOffset = 2 * kPointerSize;
1596 static const int kSubjectOffset = 3 * kPointerSize;
1597 static const int kJSRegExpOffset = 4 * kPointerSize;
1598
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001599 Label runtime;
1600 Factory* factory = masm->isolate()->factory();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001601
1602 // Ensure that a RegExp stack is allocated.
1603 ExternalReference address_of_regexp_stack_memory_address =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001604 ExternalReference::address_of_regexp_stack_memory_address(
1605 masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001606 ExternalReference address_of_regexp_stack_memory_size =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001607 ExternalReference::address_of_regexp_stack_memory_size(masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001608 __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001609 __ test(ebx, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001610 __ j(zero, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001611
1612 // Check that the first argument is a JSRegExp object.
1613 __ mov(eax, Operand(esp, kJSRegExpOffset));
1614 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001615 __ JumpIfSmi(eax, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001616 __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx);
1617 __ j(not_equal, &runtime);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001618
ricow@chromium.org65fae842010-08-25 15:26:24 +00001619 // Check that the RegExp has been compiled (data contains a fixed array).
1620 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset));
1621 if (FLAG_debug_code) {
1622 __ test(ecx, Immediate(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +00001623 __ Check(not_zero, kUnexpectedTypeForRegExpDataFixedArrayExpected);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001624 __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx);
danno@chromium.org59400602013-08-13 17:09:37 +00001625 __ Check(equal, kUnexpectedTypeForRegExpDataFixedArrayExpected);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001626 }
1627
1628 // ecx: RegExp data (FixedArray)
1629 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
1630 __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001631 __ cmp(ebx, Immediate(Smi::FromInt(JSRegExp::IRREGEXP)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001632 __ j(not_equal, &runtime);
1633
1634 // ecx: RegExp data (FixedArray)
1635 // Check that the number of captures fit in the static offsets vector buffer.
1636 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001637 // Check (number_of_captures + 1) * 2 <= offsets vector size
1638 // Or number_of_captures * 2 <= offsets vector size - 2
1639 // Multiplying by 2 comes for free since edx is smi-tagged.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001640 STATIC_ASSERT(kSmiTag == 0);
1641 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001642 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2);
1643 __ cmp(edx, Isolate::kJSRegexpStaticOffsetsVectorSize - 2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001644 __ j(above, &runtime);
1645
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001646 // Reset offset for possibly sliced string.
1647 __ Set(edi, Immediate(0));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001648 __ mov(eax, Operand(esp, kSubjectOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001649 __ JumpIfSmi(eax, &runtime);
1650 __ mov(edx, eax); // Make a copy of the original subject string.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001651 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
1652 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001653
1654 // eax: subject string
1655 // edx: subject string
1656 // ebx: subject string instance type
1657 // ecx: RegExp data (FixedArray)
1658 // Handle subject string according to its encoding and representation:
1659 // (1) Sequential two byte? If yes, go to (9).
1660 // (2) Sequential one byte? If yes, go to (6).
1661 // (3) Anything but sequential or cons? If yes, go to (7).
1662 // (4) Cons string. If the string is flat, replace subject with first string.
1663 // Otherwise bailout.
1664 // (5a) Is subject sequential two byte? If yes, go to (9).
1665 // (5b) Is subject external? If yes, go to (8).
1666 // (6) One byte sequential. Load regexp code for one byte.
1667 // (E) Carry on.
1668 /// [...]
1669
1670 // Deferred code at the end of the stub:
1671 // (7) Not a long external string? If yes, go to (10).
1672 // (8) External string. Make it, offset-wise, look like a sequential string.
1673 // (8a) Is the external string one byte? If yes, go to (6).
1674 // (9) Two byte sequential. Load regexp code for one byte. Go to (E).
1675 // (10) Short external string or not a string? If yes, bail out to runtime.
1676 // (11) Sliced string. Replace subject with parent. Go to (5a).
1677
1678 Label seq_one_byte_string /* 6 */, seq_two_byte_string /* 9 */,
1679 external_string /* 8 */, check_underlying /* 5a */,
1680 not_seq_nor_cons /* 7 */, check_code /* E */,
1681 not_long_external /* 10 */;
1682
1683 // (1) Sequential two byte? If yes, go to (9).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001684 __ and_(ebx, kIsNotStringMask |
1685 kStringRepresentationMask |
1686 kStringEncodingMask |
1687 kShortExternalStringMask);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001688 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001689 __ j(zero, &seq_two_byte_string); // Go to (9).
1690
1691 // (2) Sequential one byte? If yes, go to (6).
1692 // Any other sequential string must be one byte.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001693 __ and_(ebx, Immediate(kIsNotStringMask |
1694 kStringRepresentationMask |
1695 kShortExternalStringMask));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001696 __ j(zero, &seq_one_byte_string, Label::kNear); // Go to (6).
ricow@chromium.org65fae842010-08-25 15:26:24 +00001697
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001698 // (3) Anything but sequential or cons? If yes, go to (7).
1699 // We check whether the subject string is a cons, since sequential strings
1700 // have already been covered.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001701 STATIC_ASSERT(kConsStringTag < kExternalStringTag);
1702 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001703 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag);
1704 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001705 __ cmp(ebx, Immediate(kExternalStringTag));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001706 __ j(greater_equal, &not_seq_nor_cons); // Go to (7).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001707
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001708 // (4) Cons string. Check that it's flat.
1709 // Replace subject with first string and reload instance type.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001710 __ cmp(FieldOperand(eax, ConsString::kSecondOffset), factory->empty_string());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001711 __ j(not_equal, &runtime);
1712 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001713 __ bind(&check_underlying);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001714 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001715 __ mov(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1716
1717 // (5a) Is subject sequential two byte? If yes, go to (9).
1718 __ test_b(ebx, kStringRepresentationMask | kStringEncodingMask);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001719 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001720 __ j(zero, &seq_two_byte_string); // Go to (9).
1721 // (5b) Is subject external? If yes, go to (8).
1722 __ test_b(ebx, kStringRepresentationMask);
1723 // The underlying external string is never a short external string.
1724 STATIC_CHECK(ExternalString::kMaxShortLength < ConsString::kMinLength);
1725 STATIC_CHECK(ExternalString::kMaxShortLength < SlicedString::kMinLength);
1726 __ j(not_zero, &external_string); // Go to (8).
ricow@chromium.org65fae842010-08-25 15:26:24 +00001727
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001728 // eax: sequential subject string (or look-alike, external string)
1729 // edx: original subject string
ricow@chromium.org65fae842010-08-25 15:26:24 +00001730 // ecx: RegExp data (FixedArray)
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001731 // (6) One byte sequential. Load regexp code for one byte.
1732 __ bind(&seq_one_byte_string);
1733 // Load previous index and check range before edx is overwritten. We have
1734 // to use edx instead of eax here because it might have been only made to
1735 // look like a sequential string when it actually is an external string.
1736 __ mov(ebx, Operand(esp, kPreviousIndexOffset));
1737 __ JumpIfNotSmi(ebx, &runtime);
1738 __ cmp(ebx, FieldOperand(edx, String::kLengthOffset));
1739 __ j(above_equal, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001740 __ mov(edx, FieldOperand(ecx, JSRegExp::kDataAsciiCodeOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001741 __ Set(ecx, Immediate(1)); // Type is one byte.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001742
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001743 // (E) Carry on. String handling is done.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001744 __ bind(&check_code);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001745 // edx: irregexp code
ricow@chromium.org65fae842010-08-25 15:26:24 +00001746 // Check that the irregexp code has been generated for the actual string
1747 // encoding. If it has, the field contains a code object otherwise it contains
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001748 // a smi (code flushing support).
1749 __ JumpIfSmi(edx, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001750
1751 // eax: subject string
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001752 // ebx: previous index (smi)
ricow@chromium.org65fae842010-08-25 15:26:24 +00001753 // edx: code
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001754 // ecx: encoding of subject string (1 if ASCII, 0 if two_byte);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001755 // All checks done. Now push arguments for native regexp code.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001756 Counters* counters = masm->isolate()->counters();
1757 __ IncrementCounter(counters->regexp_entry_native(), 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001758
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001759 // Isolates: note we add an additional parameter here (isolate pointer).
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001760 static const int kRegExpExecuteArguments = 9;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001761 __ EnterApiExitFrame(kRegExpExecuteArguments);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001762
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001763 // Argument 9: Pass current isolate address.
1764 __ mov(Operand(esp, 8 * kPointerSize),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001765 Immediate(ExternalReference::isolate_address(masm->isolate())));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001766
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001767 // Argument 8: Indicate that this is a direct call from JavaScript.
1768 __ mov(Operand(esp, 7 * kPointerSize), Immediate(1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001769
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001770 // Argument 7: Start (high end) of backtracking stack memory area.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001771 __ mov(esi, Operand::StaticVariable(address_of_regexp_stack_memory_address));
1772 __ add(esi, Operand::StaticVariable(address_of_regexp_stack_memory_size));
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001773 __ mov(Operand(esp, 6 * kPointerSize), esi);
1774
1775 // Argument 6: Set the number of capture registers to zero to force global
1776 // regexps to behave as non-global. This does not affect non-global regexps.
1777 __ mov(Operand(esp, 5 * kPointerSize), Immediate(0));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001778
1779 // Argument 5: static offsets vector buffer.
1780 __ mov(Operand(esp, 4 * kPointerSize),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001781 Immediate(ExternalReference::address_of_static_offsets_vector(
1782 masm->isolate())));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001783
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001784 // Argument 2: Previous index.
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001785 __ SmiUntag(ebx);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001786 __ mov(Operand(esp, 1 * kPointerSize), ebx);
1787
1788 // Argument 1: Original subject string.
1789 // The original subject is in the previous stack frame. Therefore we have to
1790 // use ebp, which points exactly to one pointer size below the previous esp.
1791 // (Because creating a new stack frame pushes the previous ebp onto the stack
1792 // and thereby moves up esp by one kPointerSize.)
1793 __ mov(esi, Operand(ebp, kSubjectOffset + kPointerSize));
1794 __ mov(Operand(esp, 0 * kPointerSize), esi);
1795
1796 // esi: original subject string
1797 // eax: underlying subject string
1798 // ebx: previous index
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001799 // ecx: encoding of subject string (1 if ASCII 0 if two_byte);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001800 // edx: code
ricow@chromium.org65fae842010-08-25 15:26:24 +00001801 // Argument 4: End of string data
1802 // Argument 3: Start of string data
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001803 // Prepare start and end index of the input.
1804 // Load the length from the original sliced string if that is the case.
1805 __ mov(esi, FieldOperand(esi, String::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001806 __ add(esi, edi); // Calculate input end wrt offset.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001807 __ SmiUntag(edi);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001808 __ add(ebx, edi); // Calculate input start wrt offset.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001809
1810 // ebx: start index of the input string
1811 // esi: end index of the input string
1812 Label setup_two_byte, setup_rest;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001813 __ test(ecx, ecx);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001814 __ j(zero, &setup_two_byte, Label::kNear);
1815 __ SmiUntag(esi);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001816 __ lea(ecx, FieldOperand(eax, esi, times_1, SeqOneByteString::kHeaderSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001817 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001818 __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqOneByteString::kHeaderSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001819 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001820 __ jmp(&setup_rest, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001821
1822 __ bind(&setup_two_byte);
1823 STATIC_ASSERT(kSmiTag == 0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001824 STATIC_ASSERT(kSmiTagSize == 1); // esi is smi (powered by 2).
1825 __ lea(ecx, FieldOperand(eax, esi, times_1, SeqTwoByteString::kHeaderSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001826 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4.
1827 __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize));
1828 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3.
1829
1830 __ bind(&setup_rest);
1831
ricow@chromium.org65fae842010-08-25 15:26:24 +00001832 // Locate the code entry and call it.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001833 __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
1834 __ call(edx);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001835
1836 // Drop arguments and come back to JS mode.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001837 __ LeaveApiExitFrame(true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001838
1839 // Check the result.
1840 Label success;
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001841 __ cmp(eax, 1);
1842 // We expect exactly one result since we force the called regexp to behave
1843 // as non-global.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001844 __ j(equal, &success);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001845 Label failure;
1846 __ cmp(eax, NativeRegExpMacroAssembler::FAILURE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001847 __ j(equal, &failure);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001848 __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION);
1849 // If not exception it can only be retry. Handle that in the runtime system.
1850 __ j(not_equal, &runtime);
1851 // Result must now be exception. If there is no pending exception already a
1852 // stack overflow (on the backtrack stack) was detected in RegExp code but
1853 // haven't created the exception yet. Handle that in the runtime system.
1854 // TODO(592): Rerunning the RegExp to get the stack overflow exception.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001855 ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001856 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001857 __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001858 __ mov(eax, Operand::StaticVariable(pending_exception));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001859 __ cmp(edx, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001860 __ j(equal, &runtime);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001861 // For exception, throw the exception again.
1862
1863 // Clear the pending exception variable.
1864 __ mov(Operand::StaticVariable(pending_exception), edx);
1865
1866 // Special handling of termination exceptions which are uncatchable
1867 // by javascript code.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001868 __ cmp(eax, factory->termination_exception());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001869 Label throw_termination_exception;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001870 __ j(equal, &throw_termination_exception, Label::kNear);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001871
1872 // Handle normal exception by following handler chain.
1873 __ Throw(eax);
1874
1875 __ bind(&throw_termination_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001876 __ ThrowUncatchable(eax);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001877
ricow@chromium.org65fae842010-08-25 15:26:24 +00001878 __ bind(&failure);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001879 // For failure to match, return null.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001880 __ mov(eax, factory->null_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001881 __ ret(4 * kPointerSize);
1882
1883 // Load RegExp data.
1884 __ bind(&success);
1885 __ mov(eax, Operand(esp, kJSRegExpOffset));
1886 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset));
1887 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset));
1888 // Calculate number of capture registers (number_of_captures + 1) * 2.
1889 STATIC_ASSERT(kSmiTag == 0);
1890 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001891 __ add(edx, Immediate(2)); // edx was a smi.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001892
1893 // edx: Number of capture registers
1894 // Load last_match_info which is still known to be a fast case JSArray.
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001895 // Check that the fourth object is a JSArray object.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001896 __ mov(eax, Operand(esp, kLastMatchInfoOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001897 __ JumpIfSmi(eax, &runtime);
1898 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
1899 __ j(not_equal, &runtime);
1900 // Check that the JSArray is in fast case.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001901 __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001902 __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset));
1903 __ cmp(eax, factory->fixed_array_map());
1904 __ j(not_equal, &runtime);
1905 // Check that the last match info has space for the capture registers and the
1906 // additional information.
1907 __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset));
1908 __ SmiUntag(eax);
1909 __ sub(eax, Immediate(RegExpImpl::kLastMatchOverhead));
1910 __ cmp(edx, eax);
1911 __ j(greater, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001912
1913 // ebx: last_match_info backing store (FixedArray)
1914 // edx: number of capture registers
1915 // Store the capture count.
1916 __ SmiTag(edx); // Number of capture registers to smi.
1917 __ mov(FieldOperand(ebx, RegExpImpl::kLastCaptureCountOffset), edx);
1918 __ SmiUntag(edx); // Number of capture registers back from smi.
1919 // Store last subject and last input.
1920 __ mov(eax, Operand(esp, kSubjectOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001921 __ mov(ecx, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001922 __ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001923 __ RecordWriteField(ebx,
1924 RegExpImpl::kLastSubjectOffset,
1925 eax,
1926 edi,
1927 kDontSaveFPRegs);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001928 __ mov(eax, ecx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001929 __ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001930 __ RecordWriteField(ebx,
1931 RegExpImpl::kLastInputOffset,
1932 eax,
1933 edi,
1934 kDontSaveFPRegs);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001935
1936 // Get the static offsets vector filled by the native regexp code.
1937 ExternalReference address_of_static_offsets_vector =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001938 ExternalReference::address_of_static_offsets_vector(masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001939 __ mov(ecx, Immediate(address_of_static_offsets_vector));
1940
1941 // ebx: last_match_info backing store (FixedArray)
1942 // ecx: offsets vector
1943 // edx: number of capture registers
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001944 Label next_capture, done;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001945 // Capture register counter starts from number of capture registers and
1946 // counts down until wraping after zero.
1947 __ bind(&next_capture);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001948 __ sub(edx, Immediate(1));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001949 __ j(negative, &done, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001950 // Read the value from the static offsets vector buffer.
1951 __ mov(edi, Operand(ecx, edx, times_int_size, 0));
1952 __ SmiTag(edi);
1953 // Store the smi value in the last match info.
1954 __ mov(FieldOperand(ebx,
1955 edx,
1956 times_pointer_size,
1957 RegExpImpl::kFirstCaptureOffset),
1958 edi);
1959 __ jmp(&next_capture);
1960 __ bind(&done);
1961
1962 // Return last match info.
1963 __ mov(eax, Operand(esp, kLastMatchInfoOffset));
1964 __ ret(4 * kPointerSize);
1965
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001966 // Do the runtime call to execute the regexp.
1967 __ bind(&runtime);
1968 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
1969
1970 // Deferred code for string handling.
1971 // (7) Not a long external string? If yes, go to (10).
1972 __ bind(&not_seq_nor_cons);
1973 // Compare flags are still set from (3).
1974 __ j(greater, &not_long_external, Label::kNear); // Go to (10).
1975
1976 // (8) External string. Short external strings have been ruled out.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001977 __ bind(&external_string);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001978 // Reload instance type.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001979 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
1980 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1981 if (FLAG_debug_code) {
1982 // Assert that we do not have a cons or slice (indirect strings) here.
1983 // Sequential strings have already been ruled out.
1984 __ test_b(ebx, kIsIndirectStringMask);
danno@chromium.org59400602013-08-13 17:09:37 +00001985 __ Assert(zero, kExternalStringExpectedButNotFound);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001986 }
1987 __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset));
1988 // Move the pointer so that offset-wise, it looks like a sequential string.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001989 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001990 __ sub(eax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
1991 STATIC_ASSERT(kTwoByteStringTag == 0);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001992 // (8a) Is the external string one byte? If yes, go to (6).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001993 __ test_b(ebx, kStringEncodingMask);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001994 __ j(not_zero, &seq_one_byte_string); // Goto (6).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001995
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001996 // eax: sequential subject string (or look-alike, external string)
1997 // edx: original subject string
1998 // ecx: RegExp data (FixedArray)
1999 // (9) Two byte sequential. Load regexp code for one byte. Go to (E).
2000 __ bind(&seq_two_byte_string);
2001 // Load previous index and check range before edx is overwritten. We have
2002 // to use edx instead of eax here because it might have been only made to
2003 // look like a sequential string when it actually is an external string.
2004 __ mov(ebx, Operand(esp, kPreviousIndexOffset));
2005 __ JumpIfNotSmi(ebx, &runtime);
2006 __ cmp(ebx, FieldOperand(edx, String::kLengthOffset));
2007 __ j(above_equal, &runtime);
2008 __ mov(edx, FieldOperand(ecx, JSRegExp::kDataUC16CodeOffset));
2009 __ Set(ecx, Immediate(0)); // Type is two byte.
2010 __ jmp(&check_code); // Go to (E).
2011
2012 // (10) Not a string or a short external string? If yes, bail out to runtime.
2013 __ bind(&not_long_external);
2014 // Catch non-string subject or short external string.
2015 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0);
2016 __ test(ebx, Immediate(kIsNotStringMask | kShortExternalStringTag));
2017 __ j(not_zero, &runtime);
2018
2019 // (11) Sliced string. Replace subject with parent. Go to (5a).
2020 // Load offset into edi and replace subject string with parent.
2021 __ mov(edi, FieldOperand(eax, SlicedString::kOffsetOffset));
2022 __ mov(eax, FieldOperand(eax, SlicedString::kParentOffset));
2023 __ jmp(&check_underlying); // Go to (5a).
ricow@chromium.org65fae842010-08-25 15:26:24 +00002024#endif // V8_INTERPRETED_REGEXP
2025}
2026
2027
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002028void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
2029 const int kMaxInlineLength = 100;
2030 Label slowcase;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002031 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002032 __ mov(ebx, Operand(esp, kPointerSize * 3));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002033 __ JumpIfNotSmi(ebx, &slowcase);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002034 __ cmp(ebx, Immediate(Smi::FromInt(kMaxInlineLength)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002035 __ j(above, &slowcase);
2036 // Smi-tagging is equivalent to multiplying by 2.
2037 STATIC_ASSERT(kSmiTag == 0);
2038 STATIC_ASSERT(kSmiTagSize == 1);
2039 // Allocate RegExpResult followed by FixedArray with size in ebx.
2040 // JSArray: [Map][empty properties][Elements][Length-smi][index][input]
2041 // Elements: [Map][Length][..elements..]
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002042 __ Allocate(JSRegExpResult::kSize + FixedArray::kHeaderSize,
2043 times_pointer_size,
2044 ebx, // In: Number of elements as a smi
2045 REGISTER_VALUE_IS_SMI,
2046 eax, // Out: Start of allocation (tagged).
2047 ecx, // Out: End of allocation.
2048 edx, // Scratch register
2049 &slowcase,
2050 TAG_OBJECT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002051 // eax: Start of allocated area, object-tagged.
2052
2053 // Set JSArray map to global.regexp_result_map().
2054 // Set empty properties FixedArray.
2055 // Set elements to point to FixedArray allocated right after the JSArray.
2056 // Interleave operations for better latency.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002057 __ mov(edx, ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002058 Factory* factory = masm->isolate()->factory();
2059 __ mov(ecx, Immediate(factory->empty_fixed_array()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002060 __ lea(ebx, Operand(eax, JSRegExpResult::kSize));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002061 __ mov(edx, FieldOperand(edx, GlobalObject::kNativeContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002062 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx);
2063 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
2064 __ mov(edx, ContextOperand(edx, Context::REGEXP_RESULT_MAP_INDEX));
2065 __ mov(FieldOperand(eax, HeapObject::kMapOffset), edx);
2066
2067 // Set input, index and length fields from arguments.
2068 __ mov(ecx, Operand(esp, kPointerSize * 1));
2069 __ mov(FieldOperand(eax, JSRegExpResult::kInputOffset), ecx);
2070 __ mov(ecx, Operand(esp, kPointerSize * 2));
2071 __ mov(FieldOperand(eax, JSRegExpResult::kIndexOffset), ecx);
2072 __ mov(ecx, Operand(esp, kPointerSize * 3));
2073 __ mov(FieldOperand(eax, JSArray::kLengthOffset), ecx);
2074
2075 // Fill out the elements FixedArray.
2076 // eax: JSArray.
2077 // ebx: FixedArray.
2078 // ecx: Number of elements in array, as smi.
2079
2080 // Set map.
2081 __ mov(FieldOperand(ebx, HeapObject::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002082 Immediate(factory->fixed_array_map()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002083 // Set length.
2084 __ mov(FieldOperand(ebx, FixedArray::kLengthOffset), ecx);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002085 // Fill contents of fixed-array with undefined.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002086 __ SmiUntag(ecx);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002087 __ mov(edx, Immediate(factory->undefined_value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002088 __ lea(ebx, FieldOperand(ebx, FixedArray::kHeaderSize));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002089 // Fill fixed array elements with undefined.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002090 // eax: JSArray.
2091 // ecx: Number of elements to fill.
2092 // ebx: Start of elements in FixedArray.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002093 // edx: undefined.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002094 Label loop;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002095 __ test(ecx, ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002096 __ bind(&loop);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002097 __ j(less_equal, &done, Label::kNear); // Jump if ecx is negative or zero.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002098 __ sub(ecx, Immediate(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002099 __ mov(Operand(ebx, ecx, times_pointer_size, 0), edx);
2100 __ jmp(&loop);
2101
2102 __ bind(&done);
2103 __ ret(3 * kPointerSize);
2104
2105 __ bind(&slowcase);
2106 __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1);
2107}
2108
2109
ricow@chromium.org65fae842010-08-25 15:26:24 +00002110static int NegativeComparisonResult(Condition cc) {
2111 ASSERT(cc != equal);
2112 ASSERT((cc == less) || (cc == less_equal)
2113 || (cc == greater) || (cc == greater_equal));
2114 return (cc == greater || cc == greater_equal) ? LESS : GREATER;
2115}
2116
ricow@chromium.org65fae842010-08-25 15:26:24 +00002117
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002118static void CheckInputType(MacroAssembler* masm,
2119 Register input,
2120 CompareIC::State expected,
2121 Label* fail) {
2122 Label ok;
2123 if (expected == CompareIC::SMI) {
2124 __ JumpIfNotSmi(input, fail);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002125 } else if (expected == CompareIC::NUMBER) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002126 __ JumpIfSmi(input, &ok);
2127 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
2128 Immediate(masm->isolate()->factory()->heap_number_map()));
2129 __ j(not_equal, fail);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002130 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002131 // We could be strict about internalized/non-internalized here, but as long as
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002132 // hydrogen doesn't care, the stub doesn't have to care either.
2133 __ bind(&ok);
2134}
2135
2136
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002137static void BranchIfNotInternalizedString(MacroAssembler* masm,
2138 Label* label,
2139 Register object,
2140 Register scratch) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002141 __ JumpIfSmi(object, label);
2142 __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset));
2143 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00002144 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
2145 __ test(scratch, Immediate(kIsNotStringMask | kIsNotInternalizedMask));
2146 __ j(not_zero, label);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002147}
2148
2149
2150void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
2151 Label check_unequal_objects;
2152 Condition cc = GetCondition();
2153
2154 Label miss;
2155 CheckInputType(masm, edx, left_, &miss);
2156 CheckInputType(masm, eax, right_, &miss);
2157
2158 // Compare two smis.
2159 Label non_smi, smi_done;
2160 __ mov(ecx, edx);
2161 __ or_(ecx, eax);
2162 __ JumpIfNotSmi(ecx, &non_smi, Label::kNear);
2163 __ sub(edx, eax); // Return on the result of the subtraction.
2164 __ j(no_overflow, &smi_done, Label::kNear);
2165 __ not_(edx); // Correct sign in case of overflow. edx is never 0 here.
2166 __ bind(&smi_done);
2167 __ mov(eax, edx);
2168 __ ret(0);
2169 __ bind(&non_smi);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002170
ricow@chromium.org65fae842010-08-25 15:26:24 +00002171 // NOTICE! This code is only reached after a smi-fast-case check, so
2172 // it is certain that at least one operand isn't a smi.
2173
2174 // Identical objects can be compared fast, but there are some tricky cases
2175 // for NaN and undefined.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002176 Label generic_heap_number_comparison;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002177 {
2178 Label not_identical;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002179 __ cmp(eax, edx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002180 __ j(not_equal, &not_identical);
2181
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002182 if (cc != equal) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002183 // Check for undefined. undefined OP undefined is false even though
2184 // undefined == undefined.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002185 Label check_for_nan;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002186 __ cmp(edx, masm->isolate()->factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002187 __ j(not_equal, &check_for_nan, Label::kNear);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002188 __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002189 __ ret(0);
2190 __ bind(&check_for_nan);
2191 }
2192
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002193 // Test for NaN. Compare heap numbers in a general way,
2194 // to hanlde NaNs correctly.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002195 __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
2196 Immediate(masm->isolate()->factory()->heap_number_map()));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002197 __ j(equal, &generic_heap_number_comparison, Label::kNear);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002198 if (cc != equal) {
2199 // Call runtime on identical JSObjects. Otherwise return equal.
2200 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
2201 __ j(above_equal, &not_identical);
2202 }
2203 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
2204 __ ret(0);
2205
ricow@chromium.org65fae842010-08-25 15:26:24 +00002206
2207 __ bind(&not_identical);
2208 }
2209
2210 // Strict equality can quickly decide whether objects are equal.
2211 // Non-strict object equality is slower, so it is handled later in the stub.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002212 if (cc == equal && strict()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002213 Label slow; // Fallthrough label.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002214 Label not_smis;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002215 // If we're doing a strict equality comparison, we don't have to do
2216 // type conversion, so we generate code to do fast comparison for objects
2217 // and oddballs. Non-smi numbers and strings still go through the usual
2218 // slow-case code.
2219 // If either is a Smi (we know that not both are), then they can only
2220 // be equal if the other is a HeapNumber. If so, use the slow case.
2221 STATIC_ASSERT(kSmiTag == 0);
2222 ASSERT_EQ(0, Smi::FromInt(0));
2223 __ mov(ecx, Immediate(kSmiTagMask));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002224 __ and_(ecx, eax);
2225 __ test(ecx, edx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002226 __ j(not_zero, &not_smis, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002227 // One operand is a smi.
2228
2229 // Check whether the non-smi is a heap number.
2230 STATIC_ASSERT(kSmiTagMask == 1);
2231 // ecx still holds eax & kSmiTag, which is either zero or one.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002232 __ sub(ecx, Immediate(0x01));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002233 __ mov(ebx, edx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002234 __ xor_(ebx, eax);
2235 __ and_(ebx, ecx); // ebx holds either 0 or eax ^ edx.
2236 __ xor_(ebx, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002237 // if eax was smi, ebx is now edx, else eax.
2238
2239 // Check if the non-smi operand is a heap number.
2240 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002241 Immediate(masm->isolate()->factory()->heap_number_map()));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002242 // If heap number, handle it in the slow case.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002243 __ j(equal, &slow, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002244 // Return non-equal (ebx is not zero)
2245 __ mov(eax, ebx);
2246 __ ret(0);
2247
2248 __ bind(&not_smis);
2249 // If either operand is a JSObject or an oddball value, then they are not
2250 // equal since their pointers are different
2251 // There is no test for undetectability in strict equality.
2252
2253 // Get the type of the first operand.
2254 // If the first object is a JS object, we have done pointer comparison.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002255 Label first_non_object;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002256 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
2257 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002258 __ j(below, &first_non_object, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002259
2260 // Return non-zero (eax is not zero)
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002261 Label return_not_equal;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002262 STATIC_ASSERT(kHeapObjectTag != 0);
2263 __ bind(&return_not_equal);
2264 __ ret(0);
2265
2266 __ bind(&first_non_object);
2267 // Check for oddballs: true, false, null, undefined.
2268 __ CmpInstanceType(ecx, ODDBALL_TYPE);
2269 __ j(equal, &return_not_equal);
2270
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002271 __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ecx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002272 __ j(above_equal, &return_not_equal);
2273
2274 // Check for oddballs: true, false, null, undefined.
2275 __ CmpInstanceType(ecx, ODDBALL_TYPE);
2276 __ j(equal, &return_not_equal);
2277
2278 // Fall through to the general case.
2279 __ bind(&slow);
2280 }
2281
2282 // Generate the number comparison code.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002283 Label non_number_comparison;
2284 Label unordered;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002285 __ bind(&generic_heap_number_comparison);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002286 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002287 CpuFeatureScope use_sse2(masm, SSE2);
2288 CpuFeatureScope use_cmov(masm, CMOV);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002289
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002290 FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison);
2291 __ ucomisd(xmm0, xmm1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002292
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002293 // Don't base result on EFLAGS when a NaN is involved.
2294 __ j(parity_even, &unordered, Label::kNear);
2295 // Return a result of -1, 0, or 1, based on EFLAGS.
2296 __ mov(eax, 0); // equal
2297 __ mov(ecx, Immediate(Smi::FromInt(1)));
2298 __ cmov(above, eax, ecx);
2299 __ mov(ecx, Immediate(Smi::FromInt(-1)));
2300 __ cmov(below, eax, ecx);
2301 __ ret(0);
2302 } else {
2303 FloatingPointHelper::CheckFloatOperands(
2304 masm, &non_number_comparison, ebx);
2305 FloatingPointHelper::LoadFloatOperand(masm, eax);
2306 FloatingPointHelper::LoadFloatOperand(masm, edx);
2307 __ FCmp();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002308
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002309 // Don't base result on EFLAGS when a NaN is involved.
2310 __ j(parity_even, &unordered, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002311
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002312 Label below_label, above_label;
2313 // Return a result of -1, 0, or 1, based on EFLAGS.
2314 __ j(below, &below_label, Label::kNear);
2315 __ j(above, &above_label, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002316
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002317 __ Set(eax, Immediate(0));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002318 __ ret(0);
2319
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002320 __ bind(&below_label);
2321 __ mov(eax, Immediate(Smi::FromInt(-1)));
2322 __ ret(0);
2323
2324 __ bind(&above_label);
2325 __ mov(eax, Immediate(Smi::FromInt(1)));
2326 __ ret(0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002327 }
2328
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002329 // If one of the numbers was NaN, then the result is always false.
2330 // The cc is never not-equal.
2331 __ bind(&unordered);
2332 ASSERT(cc != not_equal);
2333 if (cc == less || cc == less_equal) {
2334 __ mov(eax, Immediate(Smi::FromInt(1)));
2335 } else {
2336 __ mov(eax, Immediate(Smi::FromInt(-1)));
2337 }
2338 __ ret(0);
2339
2340 // The number comparison code did not provide a valid result.
2341 __ bind(&non_number_comparison);
2342
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002343 // Fast negative check for internalized-to-internalized equality.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002344 Label check_for_strings;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002345 if (cc == equal) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002346 BranchIfNotInternalizedString(masm, &check_for_strings, eax, ecx);
2347 BranchIfNotInternalizedString(masm, &check_for_strings, edx, ecx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002348
2349 // We've already checked for object identity, so if both operands
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002350 // are internalized they aren't equal. Register eax already holds a
ricow@chromium.org65fae842010-08-25 15:26:24 +00002351 // non-zero value, which indicates not equal, so just return.
2352 __ ret(0);
2353 }
2354
2355 __ bind(&check_for_strings);
2356
2357 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx,
2358 &check_unequal_objects);
2359
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002360 // Inline comparison of ASCII strings.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002361 if (cc == equal) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002362 StringCompareStub::GenerateFlatAsciiStringEquals(masm,
ricow@chromium.org65fae842010-08-25 15:26:24 +00002363 edx,
2364 eax,
2365 ecx,
lrn@chromium.org1c092762011-05-09 09:42:16 +00002366 ebx);
2367 } else {
2368 StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
2369 edx,
2370 eax,
2371 ecx,
2372 ebx,
2373 edi);
2374 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002375#ifdef DEBUG
danno@chromium.org59400602013-08-13 17:09:37 +00002376 __ Abort(kUnexpectedFallThroughFromStringComparison);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002377#endif
2378
2379 __ bind(&check_unequal_objects);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002380 if (cc == equal && !strict()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002381 // Non-strict equality. Objects are unequal if
2382 // they are both JSObjects and not undetectable,
2383 // and their pointers are different.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002384 Label not_both_objects;
2385 Label return_unequal;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002386 // At most one is a smi, so we can test for smi by adding the two.
2387 // A smi plus a heap object has the low bit set, a heap object plus
2388 // a heap object has the low bit clear.
2389 STATIC_ASSERT(kSmiTag == 0);
2390 STATIC_ASSERT(kSmiTagMask == 1);
2391 __ lea(ecx, Operand(eax, edx, times_1, 0));
2392 __ test(ecx, Immediate(kSmiTagMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002393 __ j(not_zero, &not_both_objects, Label::kNear);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002394 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002395 __ j(below, &not_both_objects, Label::kNear);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002396 __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ebx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002397 __ j(below, &not_both_objects, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002398 // We do not bail out after this point. Both are JSObjects, and
2399 // they are equal if and only if both are undetectable.
2400 // The and of the undetectable flags is 1 if and only if they are equal.
2401 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
2402 1 << Map::kIsUndetectable);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002403 __ j(zero, &return_unequal, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002404 __ test_b(FieldOperand(ebx, Map::kBitFieldOffset),
2405 1 << Map::kIsUndetectable);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002406 __ j(zero, &return_unequal, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002407 // The objects are both undetectable, so they both compare as the value
2408 // undefined, and are equal.
2409 __ Set(eax, Immediate(EQUAL));
2410 __ bind(&return_unequal);
2411 // Return non-equal by returning the non-zero object pointer in eax,
2412 // or return equal if we fell through to here.
2413 __ ret(0); // rax, rdx were pushed
2414 __ bind(&not_both_objects);
2415 }
2416
2417 // Push arguments below the return address.
2418 __ pop(ecx);
2419 __ push(edx);
2420 __ push(eax);
2421
2422 // Figure out which native to call and setup the arguments.
2423 Builtins::JavaScript builtin;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002424 if (cc == equal) {
2425 builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002426 } else {
2427 builtin = Builtins::COMPARE;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002428 __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002429 }
2430
2431 // Restore return address on the stack.
2432 __ push(ecx);
2433
2434 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
2435 // tagged as a small integer.
2436 __ InvokeBuiltin(builtin, JUMP_FUNCTION);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002437
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002438 __ bind(&miss);
2439 GenerateMiss(masm);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002440}
2441
2442
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002443static void GenerateRecordCallTarget(MacroAssembler* masm) {
2444 // Cache the called function in a global property cell. Cache states
2445 // are uninitialized, monomorphic (indicated by a JSFunction), and
2446 // megamorphic.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002447 // eax : number of arguments to the construct function
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002448 // ebx : cache cell for call target
2449 // edi : the function to call
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002450 Isolate* isolate = masm->isolate();
2451 Label initialize, done, miss, megamorphic, not_array_function;
2452
2453 // Load the cache state into ecx.
danno@chromium.org41728482013-06-12 22:31:22 +00002454 __ mov(ecx, FieldOperand(ebx, Cell::kValueOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002455
2456 // A monomorphic cache hit or an already megamorphic state: invoke the
2457 // function without changing the state.
2458 __ cmp(ecx, edi);
2459 __ j(equal, &done);
2460 __ cmp(ecx, Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
2461 __ j(equal, &done);
2462
danno@chromium.orgbee51992013-07-10 14:57:15 +00002463 // If we came here, we need to see if we are the array function.
2464 // If we didn't have a matching function, and we didn't find the megamorph
2465 // sentinel, then we have in the cell either some other function or an
2466 // AllocationSite. Do a map check on the object in ecx.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002467 Handle<Map> allocation_site_map =
2468 masm->isolate()->factory()->allocation_site_map();
danno@chromium.orgbee51992013-07-10 14:57:15 +00002469 __ cmp(FieldOperand(ecx, 0), Immediate(allocation_site_map));
2470 __ j(not_equal, &miss);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002471
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002472 // Load the global or builtins object from the current context
2473 __ LoadGlobalContext(ecx);
2474 // Make sure the function is the Array() function
2475 __ cmp(edi, Operand(ecx,
2476 Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
2477 __ j(not_equal, &megamorphic);
2478 __ jmp(&done);
2479
2480 __ bind(&miss);
2481
2482 // A monomorphic miss (i.e, here the cache is not uninitialized) goes
2483 // megamorphic.
2484 __ cmp(ecx, Immediate(TypeFeedbackCells::UninitializedSentinel(isolate)));
2485 __ j(equal, &initialize);
2486 // MegamorphicSentinel is an immortal immovable object (undefined) so no
2487 // write-barrier is needed.
2488 __ bind(&megamorphic);
danno@chromium.org41728482013-06-12 22:31:22 +00002489 __ mov(FieldOperand(ebx, Cell::kValueOffset),
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002490 Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
2491 __ jmp(&done, Label::kNear);
2492
2493 // An uninitialized cache is patched with the function or sentinel to
2494 // indicate the ElementsKind if function is the Array constructor.
2495 __ bind(&initialize);
2496 __ LoadGlobalContext(ecx);
2497 // Make sure the function is the Array() function
2498 __ cmp(edi, Operand(ecx,
2499 Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
2500 __ j(not_equal, &not_array_function);
2501
danno@chromium.orgbee51992013-07-10 14:57:15 +00002502 // The target function is the Array constructor,
2503 // Create an AllocationSite if we don't already have it, store it in the cell
2504 {
2505 FrameScope scope(masm, StackFrame::INTERNAL);
2506
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002507 // Arguments register must be smi-tagged to call out.
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002508 __ SmiTag(eax);
danno@chromium.orgbee51992013-07-10 14:57:15 +00002509 __ push(eax);
2510 __ push(edi);
2511 __ push(ebx);
2512
2513 CreateAllocationSiteStub create_stub;
2514 __ CallStub(&create_stub);
2515
2516 __ pop(ebx);
2517 __ pop(edi);
2518 __ pop(eax);
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002519 __ SmiUntag(eax);
danno@chromium.orgbee51992013-07-10 14:57:15 +00002520 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002521 __ jmp(&done);
2522
2523 __ bind(&not_array_function);
danno@chromium.org41728482013-06-12 22:31:22 +00002524 __ mov(FieldOperand(ebx, Cell::kValueOffset), edi);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002525 // No need for a write barrier here - cells are rescanned.
2526
2527 __ bind(&done);
2528}
2529
2530
ricow@chromium.org65fae842010-08-25 15:26:24 +00002531void CallFunctionStub::Generate(MacroAssembler* masm) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002532 // ebx : cache cell for call target
danno@chromium.orgc612e022011-11-10 11:38:15 +00002533 // edi : the function to call
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002534 Isolate* isolate = masm->isolate();
lrn@chromium.org34e60782011-09-15 07:25:40 +00002535 Label slow, non_function;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002536
rossberg@chromium.org9ed27462014-01-07 14:16:41 +00002537 // Check that the function really is a JavaScript function.
2538 __ JumpIfSmi(edi, &non_function);
2539
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002540 // Goto slow case if we do not have a function.
2541 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2542 __ j(not_equal, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002543
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002544 if (RecordCallTarget()) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002545 GenerateRecordCallTarget(masm);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002546 }
2547
ricow@chromium.org65fae842010-08-25 15:26:24 +00002548 // Fast-case: Just invoke the function.
2549 ParameterCount actual(argc_);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002550
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002551 __ InvokeFunction(edi, actual, JUMP_FUNCTION, NullCallWrapper());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002552
2553 // Slow-case: Non-function called.
2554 __ bind(&slow);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002555 if (RecordCallTarget()) {
2556 // If there is a call target cache, mark it megamorphic in the
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002557 // non-function case. MegamorphicSentinel is an immortal immovable
2558 // object (undefined) so no write barrier is needed.
danno@chromium.org41728482013-06-12 22:31:22 +00002559 __ mov(FieldOperand(ebx, Cell::kValueOffset),
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002560 Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002561 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00002562 // Check for function proxy.
2563 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
2564 __ j(not_equal, &non_function);
2565 __ pop(ecx);
2566 __ push(edi); // put proxy as additional argument under return address
2567 __ push(ecx);
2568 __ Set(eax, Immediate(argc_ + 1));
2569 __ Set(ebx, Immediate(0));
lrn@chromium.org34e60782011-09-15 07:25:40 +00002570 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
2571 {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002572 Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline();
lrn@chromium.org34e60782011-09-15 07:25:40 +00002573 __ jmp(adaptor, RelocInfo::CODE_TARGET);
2574 }
2575
ricow@chromium.org65fae842010-08-25 15:26:24 +00002576 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
2577 // of the original receiver from the call site).
lrn@chromium.org34e60782011-09-15 07:25:40 +00002578 __ bind(&non_function);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002579 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi);
2580 __ Set(eax, Immediate(argc_));
2581 __ Set(ebx, Immediate(0));
2582 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002583 Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002584 __ jmp(adaptor, RelocInfo::CODE_TARGET);
2585}
2586
2587
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002588void CallConstructStub::Generate(MacroAssembler* masm) {
2589 // eax : number of arguments
2590 // ebx : cache cell for call target
2591 // edi : constructor function
2592 Label slow, non_function_call;
2593
2594 // Check that function is not a smi.
2595 __ JumpIfSmi(edi, &non_function_call);
2596 // Check that function is a JSFunction.
2597 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2598 __ j(not_equal, &slow);
2599
2600 if (RecordCallTarget()) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002601 GenerateRecordCallTarget(masm);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002602 }
2603
2604 // Jump to the function-specific construct stub.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002605 Register jmp_reg = ecx;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002606 __ mov(jmp_reg, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2607 __ mov(jmp_reg, FieldOperand(jmp_reg,
2608 SharedFunctionInfo::kConstructStubOffset));
2609 __ lea(jmp_reg, FieldOperand(jmp_reg, Code::kHeaderSize));
2610 __ jmp(jmp_reg);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002611
2612 // edi: called object
2613 // eax: number of arguments
2614 // ecx: object map
2615 Label do_call;
2616 __ bind(&slow);
2617 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
2618 __ j(not_equal, &non_function_call);
2619 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
2620 __ jmp(&do_call);
2621
2622 __ bind(&non_function_call);
2623 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
2624 __ bind(&do_call);
2625 // Set expected number of arguments to zero (not changing eax).
2626 __ Set(ebx, Immediate(0));
2627 Handle<Code> arguments_adaptor =
2628 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002629 __ jmp(arguments_adaptor, RelocInfo::CODE_TARGET);
2630}
2631
2632
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002633bool CEntryStub::NeedsImmovableCode() {
2634 return false;
2635}
2636
2637
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002638void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
2639 CEntryStub::GenerateAheadOfTime(isolate);
2640 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002641 StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002642 // It is important that the store buffer overflow stubs are generated first.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002643 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
danno@chromium.orgbee51992013-07-10 14:57:15 +00002644 CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
mvstanton@chromium.org182d2db2013-10-10 11:03:05 +00002645 if (Serializer::enabled()) {
2646 PlatformFeatureScope sse2(SSE2);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00002647 BinaryOpICStub::GenerateAheadOfTime(isolate);
ulan@chromium.org0f13e742014-01-03 15:51:11 +00002648 BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
mvstanton@chromium.org182d2db2013-10-10 11:03:05 +00002649 } else {
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00002650 BinaryOpICStub::GenerateAheadOfTime(isolate);
ulan@chromium.org0f13e742014-01-03 15:51:11 +00002651 BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
mvstanton@chromium.org182d2db2013-10-10 11:03:05 +00002652 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002653}
2654
2655
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002656void CodeStub::GenerateFPStubs(Isolate* isolate) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002657 if (CpuFeatures::IsSupported(SSE2)) {
2658 CEntryStub save_doubles(1, kSaveFPRegs);
2659 // Stubs might already be in the snapshot, detect that and don't regenerate,
2660 // which would lead to code stub initialization state being messed up.
2661 Code* save_doubles_code;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002662 if (!save_doubles.FindCodeInCache(&save_doubles_code, isolate)) {
2663 save_doubles_code = *(save_doubles.GetCode(isolate));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002664 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002665 isolate->set_fp_stubs_generated(true);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002666 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002667}
2668
2669
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002670void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002671 CEntryStub stub(1, kDontSaveFPRegs);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002672 stub.GetCode(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002673}
2674
2675
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002676static void JumpIfOOM(MacroAssembler* masm,
2677 Register value,
2678 Register scratch,
2679 Label* oom_label) {
2680 __ mov(scratch, value);
2681 STATIC_ASSERT(Failure::OUT_OF_MEMORY_EXCEPTION == 3);
2682 STATIC_ASSERT(kFailureTag == 3);
2683 __ and_(scratch, 0xf);
2684 __ cmp(scratch, 0xf);
2685 __ j(equal, oom_label);
2686}
2687
2688
ricow@chromium.org65fae842010-08-25 15:26:24 +00002689void CEntryStub::GenerateCore(MacroAssembler* masm,
2690 Label* throw_normal_exception,
2691 Label* throw_termination_exception,
2692 Label* throw_out_of_memory_exception,
2693 bool do_gc,
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002694 bool always_allocate_scope) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002695 // eax: result parameter for PerformGC, if any
2696 // ebx: pointer to C function (C callee-saved)
2697 // ebp: frame pointer (restored after C call)
2698 // esp: stack pointer (restored after C call)
2699 // edi: number of arguments including receiver (C callee-saved)
2700 // esi: pointer to the first argument (C callee-saved)
2701
2702 // Result returned in eax, or eax+edx if result_size_ is 2.
2703
2704 // Check stack alignment.
2705 if (FLAG_debug_code) {
2706 __ CheckStackAlignment();
2707 }
2708
2709 if (do_gc) {
2710 // Pass failure code returned from last attempt as first argument to
2711 // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the
2712 // stack alignment is known to be correct. This function takes one argument
2713 // which is passed on the stack, and we know that the stack has been
2714 // prepared to pass at least one argument.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002715 __ mov(Operand(esp, 1 * kPointerSize),
2716 Immediate(ExternalReference::isolate_address(masm->isolate())));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002717 __ mov(Operand(esp, 0 * kPointerSize), eax); // Result.
2718 __ call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY);
2719 }
2720
2721 ExternalReference scope_depth =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002722 ExternalReference::heap_always_allocate_scope_depth(masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002723 if (always_allocate_scope) {
2724 __ inc(Operand::StaticVariable(scope_depth));
2725 }
2726
2727 // Call C function.
2728 __ mov(Operand(esp, 0 * kPointerSize), edi); // argc.
2729 __ mov(Operand(esp, 1 * kPointerSize), esi); // argv.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002730 __ mov(Operand(esp, 2 * kPointerSize),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002731 Immediate(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002732 __ call(ebx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002733 // Result is in eax or edx:eax - do not destroy these registers!
2734
2735 if (always_allocate_scope) {
2736 __ dec(Operand::StaticVariable(scope_depth));
2737 }
2738
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002739 // Runtime functions should not return 'the hole'. Allowing it to escape may
2740 // lead to crashes in the IC code later.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002741 if (FLAG_debug_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002742 Label okay;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002743 __ cmp(eax, masm->isolate()->factory()->the_hole_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002744 __ j(not_equal, &okay, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002745 __ int3();
2746 __ bind(&okay);
2747 }
2748
2749 // Check for failure result.
2750 Label failure_returned;
2751 STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
2752 __ lea(ecx, Operand(eax, 1));
2753 // Lower 2 bits of ecx are 0 iff eax has failure tag.
2754 __ test(ecx, Immediate(kFailureTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002755 __ j(zero, &failure_returned);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002756
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002757 ExternalReference pending_exception_address(
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002758 Isolate::kPendingExceptionAddress, masm->isolate());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002759
2760 // Check that there is no pending exception, otherwise we
2761 // should have returned some failure value.
2762 if (FLAG_debug_code) {
2763 __ push(edx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002764 __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002765 Label okay;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002766 __ cmp(edx, Operand::StaticVariable(pending_exception_address));
2767 // Cannot use check here as it attempts to generate call into runtime.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002768 __ j(equal, &okay, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002769 __ int3();
2770 __ bind(&okay);
2771 __ pop(edx);
2772 }
2773
ricow@chromium.org65fae842010-08-25 15:26:24 +00002774 // Exit the JavaScript to C++ exit frame.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002775 __ LeaveExitFrame(save_doubles_ == kSaveFPRegs);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002776 __ ret(0);
2777
2778 // Handling of failure.
2779 __ bind(&failure_returned);
2780
2781 Label retry;
2782 // If the returned exception is RETRY_AFTER_GC continue at retry label
2783 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0);
2784 __ test(eax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002785 __ j(zero, &retry, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002786
2787 // Special handling of out of memory exceptions.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002788 JumpIfOOM(masm, eax, ecx, throw_out_of_memory_exception);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002789
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002790 // Retrieve the pending exception.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002791 __ mov(eax, Operand::StaticVariable(pending_exception_address));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002792
2793 // See if we just retrieved an OOM exception.
2794 JumpIfOOM(masm, eax, ecx, throw_out_of_memory_exception);
2795
2796 // Clear the pending exception.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002797 __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002798 __ mov(Operand::StaticVariable(pending_exception_address), edx);
2799
2800 // Special handling of termination exceptions which are uncatchable
2801 // by javascript code.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002802 __ cmp(eax, masm->isolate()->factory()->termination_exception());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002803 __ j(equal, throw_termination_exception);
2804
2805 // Handle normal exception.
2806 __ jmp(throw_normal_exception);
2807
2808 // Retry.
2809 __ bind(&retry);
2810}
2811
2812
ricow@chromium.org65fae842010-08-25 15:26:24 +00002813void CEntryStub::Generate(MacroAssembler* masm) {
2814 // eax: number of arguments including receiver
2815 // ebx: pointer to C function (C callee-saved)
2816 // ebp: frame pointer (restored after C call)
2817 // esp: stack pointer (restored after C call)
2818 // esi: current context (C callee-saved)
2819 // edi: JS function of the caller (C callee-saved)
2820
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002821 ProfileEntryHookStub::MaybeCallEntryHook(masm);
2822
ricow@chromium.org65fae842010-08-25 15:26:24 +00002823 // NOTE: Invocations of builtins may return failure objects instead
2824 // of a proper result. The builtin entry handles this by performing
2825 // a garbage collection and retrying the builtin (twice).
2826
2827 // Enter the exit frame that transitions from JavaScript to C++.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002828 __ EnterExitFrame(save_doubles_ == kSaveFPRegs);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002829
2830 // eax: result parameter for PerformGC, if any (setup below)
2831 // ebx: pointer to builtin function (C callee-saved)
2832 // ebp: frame pointer (restored after C call)
2833 // esp: stack pointer (restored after C call)
2834 // edi: number of arguments including receiver (C callee-saved)
2835 // esi: argv pointer (C callee-saved)
2836
2837 Label throw_normal_exception;
2838 Label throw_termination_exception;
2839 Label throw_out_of_memory_exception;
2840
2841 // Call into the runtime system.
2842 GenerateCore(masm,
2843 &throw_normal_exception,
2844 &throw_termination_exception,
2845 &throw_out_of_memory_exception,
2846 false,
2847 false);
2848
2849 // Do space-specific GC and retry runtime call.
2850 GenerateCore(masm,
2851 &throw_normal_exception,
2852 &throw_termination_exception,
2853 &throw_out_of_memory_exception,
2854 true,
2855 false);
2856
2857 // Do full GC and retry runtime call one final time.
2858 Failure* failure = Failure::InternalError();
2859 __ mov(eax, Immediate(reinterpret_cast<int32_t>(failure)));
2860 GenerateCore(masm,
2861 &throw_normal_exception,
2862 &throw_termination_exception,
2863 &throw_out_of_memory_exception,
2864 true,
2865 true);
2866
2867 __ bind(&throw_out_of_memory_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002868 // Set external caught exception to false.
2869 Isolate* isolate = masm->isolate();
2870 ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress,
2871 isolate);
2872 __ mov(Operand::StaticVariable(external_caught), Immediate(false));
2873
2874 // Set pending exception and eax to out of memory exception.
2875 ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
2876 isolate);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002877 Label already_have_failure;
2878 JumpIfOOM(masm, eax, ecx, &already_have_failure);
2879 __ mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException(0x1)));
2880 __ bind(&already_have_failure);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002881 __ mov(Operand::StaticVariable(pending_exception), eax);
2882 // Fall through to the next label.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002883
2884 __ bind(&throw_termination_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002885 __ ThrowUncatchable(eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002886
2887 __ bind(&throw_normal_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002888 __ Throw(eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002889}
2890
2891
2892void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002893 Label invoke, handler_entry, exit;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002894 Label not_outermost_js, not_outermost_js_2;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002895
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002896 ProfileEntryHookStub::MaybeCallEntryHook(masm);
2897
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002898 // Set up frame.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002899 __ push(ebp);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002900 __ mov(ebp, esp);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002901
2902 // Push marker in two places.
2903 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
2904 __ push(Immediate(Smi::FromInt(marker))); // context slot
2905 __ push(Immediate(Smi::FromInt(marker))); // function slot
2906 // Save callee-saved registers (C calling conventions).
2907 __ push(edi);
2908 __ push(esi);
2909 __ push(ebx);
2910
2911 // Save copies of the top frame descriptor on the stack.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002912 ExternalReference c_entry_fp(Isolate::kCEntryFPAddress, masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002913 __ push(Operand::StaticVariable(c_entry_fp));
2914
ricow@chromium.org65fae842010-08-25 15:26:24 +00002915 // If this is the outermost JS call, set js_entry_sp value.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002916 ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002917 masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002918 __ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002919 __ j(not_equal, &not_outermost_js, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002920 __ mov(Operand::StaticVariable(js_entry_sp), ebp);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002921 __ push(Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
danno@chromium.org2c26cb12012-05-03 09:06:43 +00002922 __ jmp(&invoke, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002923 __ bind(&not_outermost_js);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002924 __ push(Immediate(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002925
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002926 // Jump to a faked try block that does the invoke, with a faked catch
2927 // block that sets the pending exception.
2928 __ jmp(&invoke);
2929 __ bind(&handler_entry);
2930 handler_offset_ = handler_entry.pos();
2931 // Caught exception: Store result (exception) in the pending exception
2932 // field in the JSEnv and return a failure sentinel.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002933 ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002934 masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002935 __ mov(Operand::StaticVariable(pending_exception), eax);
2936 __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception()));
2937 __ jmp(&exit);
2938
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002939 // Invoke: Link this frame into the handler chain. There's only one
2940 // handler block in this code object, so its index is 0.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002941 __ bind(&invoke);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002942 __ PushTryHandler(StackHandler::JS_ENTRY, 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002943
2944 // Clear any pending exceptions.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002945 __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002946 __ mov(Operand::StaticVariable(pending_exception), edx);
2947
2948 // Fake a receiver (NULL).
2949 __ push(Immediate(0)); // receiver
2950
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002951 // Invoke the function by calling through JS entry trampoline builtin and
2952 // pop the faked function when we return. Notice that we cannot store a
2953 // reference to the trampoline code directly in this stub, because the
2954 // builtin stubs may not have been generated yet.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002955 if (is_construct) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002956 ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline,
2957 masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002958 __ mov(edx, Immediate(construct_entry));
2959 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002960 ExternalReference entry(Builtins::kJSEntryTrampoline,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002961 masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002962 __ mov(edx, Immediate(entry));
2963 }
2964 __ mov(edx, Operand(edx, 0)); // deref address
2965 __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002966 __ call(edx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002967
2968 // Unlink this frame from the handler chain.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002969 __ PopTryHandler();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002970
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002971 __ bind(&exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002972 // Check if the current stack frame is marked as the outermost JS frame.
2973 __ pop(ebx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002974 __ cmp(ebx, Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002975 __ j(not_equal, &not_outermost_js_2);
2976 __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0));
2977 __ bind(&not_outermost_js_2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002978
2979 // Restore the top frame descriptor from the stack.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002980 __ pop(Operand::StaticVariable(ExternalReference(
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002981 Isolate::kCEntryFPAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002982 masm->isolate())));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002983
2984 // Restore callee-saved registers (C calling conventions).
2985 __ pop(ebx);
2986 __ pop(esi);
2987 __ pop(edi);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002988 __ add(esp, Immediate(2 * kPointerSize)); // remove markers
ricow@chromium.org65fae842010-08-25 15:26:24 +00002989
2990 // Restore frame pointer and return.
2991 __ pop(ebp);
2992 __ ret(0);
2993}
2994
2995
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002996// Generate stub code for instanceof.
2997// This code can patch a call site inlined cache of the instance of check,
2998// which looks like this.
2999//
3000// 81 ff XX XX XX XX cmp edi, <the hole, patched to a map>
3001// 75 0a jne <some near label>
3002// b8 XX XX XX XX mov eax, <the hole, patched to either true or false>
3003//
3004// If call site patching is requested the stack will have the delta from the
3005// return address to the cmp instruction just below the return address. This
3006// also means that call site patching can only take place with arguments in
3007// registers. TOS looks like this when call site patching is requested
3008//
3009// esp[0] : return address
3010// esp[4] : delta from return address to cmp instruction
3011//
ricow@chromium.org65fae842010-08-25 15:26:24 +00003012void InstanceofStub::Generate(MacroAssembler* masm) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003013 // Call site inlining and patching implies arguments in registers.
3014 ASSERT(HasArgsInRegisters() || !HasCallSiteInlineCheck());
3015
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003016 // Fixed register usage throughout the stub.
3017 Register object = eax; // Object (lhs).
3018 Register map = ebx; // Map of the object.
3019 Register function = edx; // Function (rhs).
3020 Register prototype = edi; // Prototype of the function.
3021 Register scratch = ecx;
3022
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003023 // Constants describing the call site code to patch.
3024 static const int kDeltaToCmpImmediate = 2;
3025 static const int kDeltaToMov = 8;
3026 static const int kDeltaToMovImmediate = 9;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003027 static const int8_t kCmpEdiOperandByte1 = BitCast<int8_t, uint8_t>(0x3b);
3028 static const int8_t kCmpEdiOperandByte2 = BitCast<int8_t, uint8_t>(0x3d);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003029 static const int8_t kMovEaxImmediateByte = BitCast<int8_t, uint8_t>(0xb8);
3030
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003031 ASSERT_EQ(object.code(), InstanceofStub::left().code());
3032 ASSERT_EQ(function.code(), InstanceofStub::right().code());
3033
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003034 // Get the object and function - they are always both needed.
3035 Label slow, not_js_object;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003036 if (!HasArgsInRegisters()) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003037 __ mov(object, Operand(esp, 2 * kPointerSize));
3038 __ mov(function, Operand(esp, 1 * kPointerSize));
3039 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003040
3041 // Check that the left hand is a JS object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003042 __ JumpIfSmi(object, &not_js_object);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003043 __ IsObjectJSObjectType(object, map, scratch, &not_js_object);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003044
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003045 // If there is a call site cache don't look in the global cache, but do the
3046 // real lookup and update the call site cache.
3047 if (!HasCallSiteInlineCheck()) {
3048 // Look up the function and the map in the instanceof cache.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003049 Label miss;
danno@chromium.org59400602013-08-13 17:09:37 +00003050 __ CompareRoot(function, scratch, Heap::kInstanceofCacheFunctionRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003051 __ j(not_equal, &miss, Label::kNear);
danno@chromium.org59400602013-08-13 17:09:37 +00003052 __ CompareRoot(map, scratch, Heap::kInstanceofCacheMapRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003053 __ j(not_equal, &miss, Label::kNear);
danno@chromium.org59400602013-08-13 17:09:37 +00003054 __ LoadRoot(eax, Heap::kInstanceofCacheAnswerRootIndex);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003055 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
3056 __ bind(&miss);
3057 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003058
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003059 // Get the prototype of the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003060 __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003061
3062 // Check that the function prototype is a JS object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003063 __ JumpIfSmi(prototype, &slow);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003064 __ IsObjectJSObjectType(prototype, scratch, scratch, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003065
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003066 // Update the global instanceof or call site inlined cache with the current
3067 // map and function. The cached answer will be set when it is known below.
3068 if (!HasCallSiteInlineCheck()) {
danno@chromium.org59400602013-08-13 17:09:37 +00003069 __ StoreRoot(map, scratch, Heap::kInstanceofCacheMapRootIndex);
3070 __ StoreRoot(function, scratch, Heap::kInstanceofCacheFunctionRootIndex);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003071 } else {
3072 // The constants for the code patching are based on no push instructions
3073 // at the call site.
3074 ASSERT(HasArgsInRegisters());
3075 // Get return address and delta to inlined map check.
3076 __ mov(scratch, Operand(esp, 0 * kPointerSize));
3077 __ sub(scratch, Operand(esp, 1 * kPointerSize));
3078 if (FLAG_debug_code) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003079 __ cmpb(Operand(scratch, 0), kCmpEdiOperandByte1);
danno@chromium.org59400602013-08-13 17:09:37 +00003080 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheCmp1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003081 __ cmpb(Operand(scratch, 1), kCmpEdiOperandByte2);
danno@chromium.org59400602013-08-13 17:09:37 +00003082 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheCmp2);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003083 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003084 __ mov(scratch, Operand(scratch, kDeltaToCmpImmediate));
3085 __ mov(Operand(scratch, 0), map);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003086 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003087
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003088 // Loop through the prototype chain of the object looking for the function
3089 // prototype.
3090 __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003091 Label loop, is_instance, is_not_instance;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003092 __ bind(&loop);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003093 __ cmp(scratch, prototype);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003094 __ j(equal, &is_instance, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003095 Factory* factory = masm->isolate()->factory();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003096 __ cmp(scratch, Immediate(factory->null_value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003097 __ j(equal, &is_not_instance, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003098 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
3099 __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003100 __ jmp(&loop);
3101
3102 __ bind(&is_instance);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003103 if (!HasCallSiteInlineCheck()) {
danno@chromium.org59400602013-08-13 17:09:37 +00003104 __ mov(eax, Immediate(0));
3105 __ StoreRoot(eax, scratch, Heap::kInstanceofCacheAnswerRootIndex);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003106 } else {
3107 // Get return address and delta to inlined map check.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003108 __ mov(eax, factory->true_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003109 __ mov(scratch, Operand(esp, 0 * kPointerSize));
3110 __ sub(scratch, Operand(esp, 1 * kPointerSize));
3111 if (FLAG_debug_code) {
3112 __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte);
danno@chromium.org59400602013-08-13 17:09:37 +00003113 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003114 }
3115 __ mov(Operand(scratch, kDeltaToMovImmediate), eax);
3116 if (!ReturnTrueFalseObject()) {
3117 __ Set(eax, Immediate(0));
3118 }
3119 }
3120 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003121
3122 __ bind(&is_not_instance);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003123 if (!HasCallSiteInlineCheck()) {
danno@chromium.org59400602013-08-13 17:09:37 +00003124 __ mov(eax, Immediate(Smi::FromInt(1)));
3125 __ StoreRoot(eax, scratch, Heap::kInstanceofCacheAnswerRootIndex);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003126 } else {
3127 // Get return address and delta to inlined map check.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003128 __ mov(eax, factory->false_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003129 __ mov(scratch, Operand(esp, 0 * kPointerSize));
3130 __ sub(scratch, Operand(esp, 1 * kPointerSize));
3131 if (FLAG_debug_code) {
3132 __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte);
danno@chromium.org59400602013-08-13 17:09:37 +00003133 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003134 }
3135 __ mov(Operand(scratch, kDeltaToMovImmediate), eax);
3136 if (!ReturnTrueFalseObject()) {
3137 __ Set(eax, Immediate(Smi::FromInt(1)));
3138 }
3139 }
3140 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003141
3142 Label object_not_null, object_not_null_or_smi;
3143 __ bind(&not_js_object);
3144 // Before null, smi and string value checks, check that the rhs is a function
3145 // as for a non-function rhs an exception needs to be thrown.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003146 __ JumpIfSmi(function, &slow, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003147 __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003148 __ j(not_equal, &slow, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003149
3150 // Null is not instance of anything.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003151 __ cmp(object, factory->null_value());
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003152 __ j(not_equal, &object_not_null, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003153 __ Set(eax, Immediate(Smi::FromInt(1)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003154 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003155
3156 __ bind(&object_not_null);
3157 // Smi values is not instance of anything.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003158 __ JumpIfNotSmi(object, &object_not_null_or_smi, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003159 __ Set(eax, Immediate(Smi::FromInt(1)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003160 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003161
3162 __ bind(&object_not_null_or_smi);
3163 // String values is not instance of anything.
3164 Condition is_string = masm->IsObjectStringType(object, scratch, scratch);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003165 __ j(NegateCondition(is_string), &slow, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003166 __ Set(eax, Immediate(Smi::FromInt(1)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003167 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003168
3169 // Slow-case: Go through the JavaScript implementation.
3170 __ bind(&slow);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003171 if (!ReturnTrueFalseObject()) {
3172 // Tail call the builtin which returns 0 or 1.
3173 if (HasArgsInRegisters()) {
3174 // Push arguments below return address.
3175 __ pop(scratch);
3176 __ push(object);
3177 __ push(function);
3178 __ push(scratch);
3179 }
3180 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
3181 } else {
3182 // Call the builtin and convert 0/1 to true/false.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003183 {
3184 FrameScope scope(masm, StackFrame::INTERNAL);
3185 __ push(object);
3186 __ push(function);
3187 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
3188 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003189 Label true_value, done;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003190 __ test(eax, eax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003191 __ j(zero, &true_value, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003192 __ mov(eax, factory->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003193 __ jmp(&done, Label::kNear);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003194 __ bind(&true_value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003195 __ mov(eax, factory->true_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003196 __ bind(&done);
3197 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003198 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003199}
3200
3201
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003202Register InstanceofStub::left() { return eax; }
3203
3204
3205Register InstanceofStub::right() { return edx; }
3206
3207
ricow@chromium.org65fae842010-08-25 15:26:24 +00003208// -------------------------------------------------------------------------
3209// StringCharCodeAtGenerator
3210
3211void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003212 // If the receiver is a smi trigger the non-string case.
3213 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003214 __ JumpIfSmi(object_, receiver_not_string_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003215
3216 // Fetch the instance type of the receiver into result register.
3217 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
3218 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
3219 // If the receiver is not a string trigger the non-string case.
3220 __ test(result_, Immediate(kIsNotStringMask));
3221 __ j(not_zero, receiver_not_string_);
3222
3223 // If the index is non-smi trigger the non-smi case.
3224 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003225 __ JumpIfNotSmi(index_, &index_not_smi_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003226 __ bind(&got_smi_index_);
3227
3228 // Check for index out of range.
danno@chromium.orgc612e022011-11-10 11:38:15 +00003229 __ cmp(index_, FieldOperand(object_, String::kLengthOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003230 __ j(above_equal, index_out_of_range_);
3231
danno@chromium.orgc612e022011-11-10 11:38:15 +00003232 __ SmiUntag(index_);
erikcorry0ad885c2011-11-21 13:51:57 +00003233
3234 Factory* factory = masm->isolate()->factory();
3235 StringCharLoadGenerator::Generate(
3236 masm, factory, object_, index_, result_, &call_runtime_);
3237
ricow@chromium.org65fae842010-08-25 15:26:24 +00003238 __ SmiTag(result_);
3239 __ bind(&exit_);
3240}
3241
3242
3243void StringCharCodeAtGenerator::GenerateSlow(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003244 MacroAssembler* masm,
3245 const RuntimeCallHelper& call_helper) {
danno@chromium.org59400602013-08-13 17:09:37 +00003246 __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003247
3248 // Index is not a smi.
3249 __ bind(&index_not_smi_);
3250 // If index is a heap number, try converting it to an integer.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003251 __ CheckMap(index_,
3252 masm->isolate()->factory()->heap_number_map(),
3253 index_not_number_,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003254 DONT_DO_SMI_CHECK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003255 call_helper.BeforeCall(masm);
3256 __ push(object_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003257 __ push(index_); // Consumed by runtime conversion function.
3258 if (index_flags_ == STRING_INDEX_IS_NUMBER) {
3259 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
3260 } else {
3261 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
3262 // NumberToSmi discards numbers that are not exact integers.
3263 __ CallRuntime(Runtime::kNumberToSmi, 1);
3264 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00003265 if (!index_.is(eax)) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003266 // Save the conversion result before the pop instructions below
3267 // have a chance to overwrite it.
danno@chromium.orgc612e022011-11-10 11:38:15 +00003268 __ mov(index_, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003269 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003270 __ pop(object_);
3271 // Reload the instance type.
3272 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
3273 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
3274 call_helper.AfterCall(masm);
3275 // If index is still not a smi, it must be out of range.
3276 STATIC_ASSERT(kSmiTag == 0);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003277 __ JumpIfNotSmi(index_, index_out_of_range_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003278 // Otherwise, return to the fast path.
3279 __ jmp(&got_smi_index_);
3280
3281 // Call runtime. We get here when the receiver is a string and the
3282 // index is a number, but the code of getting the actual character
3283 // is too complex (e.g., when the string needs to be flattened).
3284 __ bind(&call_runtime_);
3285 call_helper.BeforeCall(masm);
3286 __ push(object_);
erikcorry0ad885c2011-11-21 13:51:57 +00003287 __ SmiTag(index_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003288 __ push(index_);
3289 __ CallRuntime(Runtime::kStringCharCodeAt, 2);
3290 if (!result_.is(eax)) {
3291 __ mov(result_, eax);
3292 }
3293 call_helper.AfterCall(masm);
3294 __ jmp(&exit_);
3295
danno@chromium.org59400602013-08-13 17:09:37 +00003296 __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003297}
3298
3299
3300// -------------------------------------------------------------------------
3301// StringCharFromCodeGenerator
3302
3303void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
3304 // Fast case of Heap::LookupSingleCharacterStringFromCode.
3305 STATIC_ASSERT(kSmiTag == 0);
3306 STATIC_ASSERT(kSmiShiftSize == 0);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003307 ASSERT(IsPowerOf2(String::kMaxOneByteCharCode + 1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003308 __ test(code_,
3309 Immediate(kSmiTagMask |
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003310 ((~String::kMaxOneByteCharCode) << kSmiTagSize)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003311 __ j(not_zero, &slow_case_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003312
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003313 Factory* factory = masm->isolate()->factory();
3314 __ Set(result_, Immediate(factory->single_character_string_cache()));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003315 STATIC_ASSERT(kSmiTag == 0);
3316 STATIC_ASSERT(kSmiTagSize == 1);
3317 STATIC_ASSERT(kSmiShiftSize == 0);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003318 // At this point code register contains smi tagged ASCII char code.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003319 __ mov(result_, FieldOperand(result_,
3320 code_, times_half_pointer_size,
3321 FixedArray::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003322 __ cmp(result_, factory->undefined_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003323 __ j(equal, &slow_case_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003324 __ bind(&exit_);
3325}
3326
3327
3328void StringCharFromCodeGenerator::GenerateSlow(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003329 MacroAssembler* masm,
3330 const RuntimeCallHelper& call_helper) {
danno@chromium.org59400602013-08-13 17:09:37 +00003331 __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003332
3333 __ bind(&slow_case_);
3334 call_helper.BeforeCall(masm);
3335 __ push(code_);
3336 __ CallRuntime(Runtime::kCharFromCode, 1);
3337 if (!result_.is(eax)) {
3338 __ mov(result_, eax);
3339 }
3340 call_helper.AfterCall(masm);
3341 __ jmp(&exit_);
3342
danno@chromium.org59400602013-08-13 17:09:37 +00003343 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003344}
3345
3346
ricow@chromium.org65fae842010-08-25 15:26:24 +00003347void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm,
3348 Register dest,
3349 Register src,
3350 Register count,
3351 Register scratch,
3352 bool ascii) {
3353 // Copy characters using rep movs of doublewords.
3354 // The destination is aligned on a 4 byte boundary because we are
3355 // copying to the beginning of a newly allocated string.
3356 ASSERT(dest.is(edi)); // rep movs destination
3357 ASSERT(src.is(esi)); // rep movs source
3358 ASSERT(count.is(ecx)); // rep movs count
3359 ASSERT(!scratch.is(dest));
3360 ASSERT(!scratch.is(src));
3361 ASSERT(!scratch.is(count));
3362
3363 // Nothing to do for zero characters.
3364 Label done;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003365 __ test(count, count);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003366 __ j(zero, &done);
3367
3368 // Make count the number of bytes to copy.
3369 if (!ascii) {
3370 __ shl(count, 1);
3371 }
3372
3373 // Don't enter the rep movs if there are less than 4 bytes to copy.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003374 Label last_bytes;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003375 __ test(count, Immediate(~3));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003376 __ j(zero, &last_bytes, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003377
3378 // Copy from edi to esi using rep movs instruction.
3379 __ mov(scratch, count);
3380 __ sar(count, 2); // Number of doublewords to copy.
3381 __ cld();
3382 __ rep_movs();
3383
3384 // Find number of bytes left.
3385 __ mov(count, scratch);
3386 __ and_(count, 3);
3387
3388 // Check if there are more bytes to copy.
3389 __ bind(&last_bytes);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003390 __ test(count, count);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003391 __ j(zero, &done);
3392
3393 // Copy remaining characters.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003394 Label loop;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003395 __ bind(&loop);
3396 __ mov_b(scratch, Operand(src, 0));
3397 __ mov_b(Operand(dest, 0), scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003398 __ add(src, Immediate(1));
3399 __ add(dest, Immediate(1));
3400 __ sub(count, Immediate(1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003401 __ j(not_zero, &loop);
3402
3403 __ bind(&done);
3404}
3405
3406
ricow@chromium.org65fae842010-08-25 15:26:24 +00003407void StringHelper::GenerateHashInit(MacroAssembler* masm,
3408 Register hash,
3409 Register character,
3410 Register scratch) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00003411 // hash = (seed + character) + ((seed + character) << 10);
3412 if (Serializer::enabled()) {
danno@chromium.org59400602013-08-13 17:09:37 +00003413 __ LoadRoot(scratch, Heap::kHashSeedRootIndex);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003414 __ SmiUntag(scratch);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00003415 __ add(scratch, character);
3416 __ mov(hash, scratch);
3417 __ shl(scratch, 10);
3418 __ add(hash, scratch);
3419 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003420 int32_t seed = masm->isolate()->heap()->HashSeed();
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00003421 __ lea(scratch, Operand(character, seed));
3422 __ shl(scratch, 10);
3423 __ lea(hash, Operand(scratch, character, times_1, seed));
3424 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003425 // hash ^= hash >> 6;
3426 __ mov(scratch, hash);
danno@chromium.org2c456792011-11-11 12:00:53 +00003427 __ shr(scratch, 6);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003428 __ xor_(hash, scratch);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003429}
3430
3431
3432void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
3433 Register hash,
3434 Register character,
3435 Register scratch) {
3436 // hash += character;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003437 __ add(hash, character);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003438 // hash += hash << 10;
3439 __ mov(scratch, hash);
3440 __ shl(scratch, 10);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003441 __ add(hash, scratch);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003442 // hash ^= hash >> 6;
3443 __ mov(scratch, hash);
danno@chromium.org2c456792011-11-11 12:00:53 +00003444 __ shr(scratch, 6);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003445 __ xor_(hash, scratch);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003446}
3447
3448
3449void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
3450 Register hash,
3451 Register scratch) {
3452 // hash += hash << 3;
3453 __ mov(scratch, hash);
3454 __ shl(scratch, 3);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003455 __ add(hash, scratch);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003456 // hash ^= hash >> 11;
3457 __ mov(scratch, hash);
danno@chromium.org2c456792011-11-11 12:00:53 +00003458 __ shr(scratch, 11);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003459 __ xor_(hash, scratch);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003460 // hash += hash << 15;
3461 __ mov(scratch, hash);
3462 __ shl(scratch, 15);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003463 __ add(hash, scratch);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003464
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003465 __ and_(hash, String::kHashBitMask);
danno@chromium.org2c456792011-11-11 12:00:53 +00003466
ricow@chromium.org65fae842010-08-25 15:26:24 +00003467 // if (hash == 0) hash = 27;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003468 Label hash_not_zero;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003469 __ j(not_zero, &hash_not_zero, Label::kNear);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003470 __ mov(hash, Immediate(StringHasher::kZeroHash));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003471 __ bind(&hash_not_zero);
3472}
3473
3474
3475void SubStringStub::Generate(MacroAssembler* masm) {
3476 Label runtime;
3477
3478 // Stack frame on entry.
3479 // esp[0]: return address
3480 // esp[4]: to
3481 // esp[8]: from
3482 // esp[12]: string
3483
3484 // Make sure first argument is a string.
3485 __ mov(eax, Operand(esp, 3 * kPointerSize));
3486 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003487 __ JumpIfSmi(eax, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003488 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx);
3489 __ j(NegateCondition(is_string), &runtime);
3490
3491 // eax: string
3492 // ebx: instance type
3493
3494 // Calculate length of sub string using the smi values.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003495 __ mov(ecx, Operand(esp, 1 * kPointerSize)); // To index.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003496 __ JumpIfNotSmi(ecx, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003497 __ mov(edx, Operand(esp, 2 * kPointerSize)); // From index.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003498 __ JumpIfNotSmi(edx, &runtime);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003499 __ sub(ecx, edx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003500 __ cmp(ecx, FieldOperand(eax, String::kLengthOffset));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003501 Label not_original_string;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003502 // Shorter than original string's length: an actual substring.
3503 __ j(below, &not_original_string, Label::kNear);
3504 // Longer than original string's length or negative: unsafe arguments.
3505 __ j(above, &runtime);
3506 // Return original string.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003507 Counters* counters = masm->isolate()->counters();
3508 __ IncrementCounter(counters->sub_string_native(), 1);
3509 __ ret(3 * kPointerSize);
3510 __ bind(&not_original_string);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003511
ulan@chromium.org2e04b582013-02-21 14:06:02 +00003512 Label single_char;
3513 __ cmp(ecx, Immediate(Smi::FromInt(1)));
3514 __ j(equal, &single_char);
3515
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003516 // eax: string
3517 // ebx: instance type
3518 // ecx: sub string length (smi)
3519 // edx: from index (smi)
3520 // Deal with different string types: update the index if necessary
3521 // and put the underlying string into edi.
3522 Label underlying_unpacked, sliced_string, seq_or_external_string;
3523 // If the string is not indirect, it can only be sequential or external.
3524 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
3525 STATIC_ASSERT(kIsIndirectStringMask != 0);
3526 __ test(ebx, Immediate(kIsIndirectStringMask));
3527 __ j(zero, &seq_or_external_string, Label::kNear);
3528
3529 Factory* factory = masm->isolate()->factory();
3530 __ test(ebx, Immediate(kSlicedNotConsMask));
3531 __ j(not_zero, &sliced_string, Label::kNear);
3532 // Cons string. Check whether it is flat, then fetch first part.
3533 // Flat cons strings have an empty second part.
3534 __ cmp(FieldOperand(eax, ConsString::kSecondOffset),
3535 factory->empty_string());
3536 __ j(not_equal, &runtime);
3537 __ mov(edi, FieldOperand(eax, ConsString::kFirstOffset));
3538 // Update instance type.
3539 __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
3540 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
3541 __ jmp(&underlying_unpacked, Label::kNear);
3542
3543 __ bind(&sliced_string);
3544 // Sliced string. Fetch parent and adjust start index by offset.
3545 __ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset));
3546 __ mov(edi, FieldOperand(eax, SlicedString::kParentOffset));
3547 // Update instance type.
3548 __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
3549 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
3550 __ jmp(&underlying_unpacked, Label::kNear);
3551
3552 __ bind(&seq_or_external_string);
3553 // Sequential or external string. Just move string to the expected register.
3554 __ mov(edi, eax);
3555
3556 __ bind(&underlying_unpacked);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003557
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003558 if (FLAG_string_slices) {
3559 Label copy_routine;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003560 // edi: underlying subject string
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003561 // ebx: instance type of underlying subject string
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003562 // edx: adjusted start index (smi)
3563 // ecx: length (smi)
3564 __ cmp(ecx, Immediate(Smi::FromInt(SlicedString::kMinLength)));
3565 // Short slice. Copy instead of slicing.
3566 __ j(less, &copy_routine);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003567 // Allocate new sliced string. At this point we do not reload the instance
3568 // type including the string encoding because we simply rely on the info
3569 // provided by the original string. It does not matter if the original
3570 // string's encoding is wrong because we always have to recheck encoding of
3571 // the newly created string's parent anyways due to externalized strings.
3572 Label two_byte_slice, set_slice_header;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003573 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003574 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
3575 __ test(ebx, Immediate(kStringEncodingMask));
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003576 __ j(zero, &two_byte_slice, Label::kNear);
3577 __ AllocateAsciiSlicedString(eax, ebx, no_reg, &runtime);
3578 __ jmp(&set_slice_header, Label::kNear);
3579 __ bind(&two_byte_slice);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003580 __ AllocateTwoByteSlicedString(eax, ebx, no_reg, &runtime);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003581 __ bind(&set_slice_header);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003582 __ mov(FieldOperand(eax, SlicedString::kLengthOffset), ecx);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003583 __ mov(FieldOperand(eax, SlicedString::kHashFieldOffset),
3584 Immediate(String::kEmptyHashField));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003585 __ mov(FieldOperand(eax, SlicedString::kParentOffset), edi);
3586 __ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003587 __ IncrementCounter(counters->sub_string_native(), 1);
3588 __ ret(3 * kPointerSize);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003589
3590 __ bind(&copy_routine);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003591 }
3592
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003593 // edi: underlying subject string
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003594 // ebx: instance type of underlying subject string
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003595 // edx: adjusted start index (smi)
3596 // ecx: length (smi)
3597 // The subject string can only be external or sequential string of either
3598 // encoding at this point.
3599 Label two_byte_sequential, runtime_drop_two, sequential_string;
3600 STATIC_ASSERT(kExternalStringTag != 0);
3601 STATIC_ASSERT(kSeqStringTag == 0);
3602 __ test_b(ebx, kExternalStringTag);
3603 __ j(zero, &sequential_string);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003604
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003605 // Handle external string.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003606 // Rule out short external strings.
3607 STATIC_CHECK(kShortExternalStringTag != 0);
3608 __ test_b(ebx, kShortExternalStringMask);
3609 __ j(not_zero, &runtime);
3610 __ mov(edi, FieldOperand(edi, ExternalString::kResourceDataOffset));
3611 // Move the pointer so that offset-wise, it looks like a sequential string.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003612 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003613 __ sub(edi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
3614
3615 __ bind(&sequential_string);
3616 // Stash away (adjusted) index and (underlying) string.
3617 __ push(edx);
3618 __ push(edi);
3619 __ SmiUntag(ecx);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003620 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003621 __ test_b(ebx, kStringEncodingMask);
3622 __ j(zero, &two_byte_sequential);
3623
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003624 // Sequential ASCII string. Allocate the result.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003625 __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime_drop_two);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003626
3627 // eax: result string
3628 // ecx: result string length
3629 __ mov(edx, esi); // esi used by following code.
3630 // Locate first character of result.
3631 __ mov(edi, eax);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003632 __ add(edi, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003633 // Load string argument and locate character of sub string start.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003634 __ pop(esi);
3635 __ pop(ebx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003636 __ SmiUntag(ebx);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003637 __ lea(esi, FieldOperand(esi, ebx, times_1, SeqOneByteString::kHeaderSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003638
3639 // eax: result string
3640 // ecx: result length
3641 // edx: original value of esi
3642 // edi: first character of result
3643 // esi: character of sub string start
3644 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true);
3645 __ mov(esi, edx); // Restore esi.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003646 __ IncrementCounter(counters->sub_string_native(), 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003647 __ ret(3 * kPointerSize);
3648
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003649 __ bind(&two_byte_sequential);
3650 // Sequential two-byte string. Allocate the result.
3651 __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime_drop_two);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003652
3653 // eax: result string
3654 // ecx: result string length
3655 __ mov(edx, esi); // esi used by following code.
3656 // Locate first character of result.
3657 __ mov(edi, eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003658 __ add(edi,
ricow@chromium.org65fae842010-08-25 15:26:24 +00003659 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
3660 // Load string argument and locate character of sub string start.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003661 __ pop(esi);
3662 __ pop(ebx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003663 // As from is a smi it is 2 times the value which matches the size of a two
3664 // byte character.
3665 STATIC_ASSERT(kSmiTag == 0);
3666 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003667 __ lea(esi, FieldOperand(esi, ebx, times_1, SeqTwoByteString::kHeaderSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003668
3669 // eax: result string
3670 // ecx: result length
3671 // edx: original value of esi
3672 // edi: first character of result
3673 // esi: character of sub string start
3674 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false);
3675 __ mov(esi, edx); // Restore esi.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003676 __ IncrementCounter(counters->sub_string_native(), 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003677 __ ret(3 * kPointerSize);
3678
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003679 // Drop pushed values on the stack before tail call.
3680 __ bind(&runtime_drop_two);
3681 __ Drop(2);
3682
ricow@chromium.org65fae842010-08-25 15:26:24 +00003683 // Just jump to runtime to create the sub string.
3684 __ bind(&runtime);
3685 __ TailCallRuntime(Runtime::kSubString, 3, 1);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00003686
3687 __ bind(&single_char);
3688 // eax: string
3689 // ebx: instance type
3690 // ecx: sub string length (smi)
3691 // edx: from index (smi)
3692 StringCharAtGenerator generator(
3693 eax, edx, ecx, eax, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
3694 generator.GenerateFast(masm);
3695 __ ret(3 * kPointerSize);
3696 generator.SkipSlow(masm, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003697}
3698
3699
lrn@chromium.org1c092762011-05-09 09:42:16 +00003700void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm,
3701 Register left,
3702 Register right,
3703 Register scratch1,
3704 Register scratch2) {
3705 Register length = scratch1;
3706
3707 // Compare lengths.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003708 Label strings_not_equal, check_zero_length;
lrn@chromium.org1c092762011-05-09 09:42:16 +00003709 __ mov(length, FieldOperand(left, String::kLengthOffset));
3710 __ cmp(length, FieldOperand(right, String::kLengthOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003711 __ j(equal, &check_zero_length, Label::kNear);
lrn@chromium.org1c092762011-05-09 09:42:16 +00003712 __ bind(&strings_not_equal);
3713 __ Set(eax, Immediate(Smi::FromInt(NOT_EQUAL)));
3714 __ ret(0);
3715
3716 // Check if the length is zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003717 Label compare_chars;
lrn@chromium.org1c092762011-05-09 09:42:16 +00003718 __ bind(&check_zero_length);
3719 STATIC_ASSERT(kSmiTag == 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003720 __ test(length, length);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003721 __ j(not_zero, &compare_chars, Label::kNear);
lrn@chromium.org1c092762011-05-09 09:42:16 +00003722 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
3723 __ ret(0);
3724
3725 // Compare characters.
3726 __ bind(&compare_chars);
3727 GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2,
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003728 &strings_not_equal, Label::kNear);
lrn@chromium.org1c092762011-05-09 09:42:16 +00003729
3730 // Characters are equal.
3731 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
3732 __ ret(0);
3733}
3734
3735
ricow@chromium.org65fae842010-08-25 15:26:24 +00003736void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
3737 Register left,
3738 Register right,
3739 Register scratch1,
3740 Register scratch2,
3741 Register scratch3) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003742 Counters* counters = masm->isolate()->counters();
3743 __ IncrementCounter(counters->string_compare_native(), 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003744
3745 // Find minimum length.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003746 Label left_shorter;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003747 __ mov(scratch1, FieldOperand(left, String::kLengthOffset));
3748 __ mov(scratch3, scratch1);
3749 __ sub(scratch3, FieldOperand(right, String::kLengthOffset));
3750
3751 Register length_delta = scratch3;
3752
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003753 __ j(less_equal, &left_shorter, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003754 // Right string is shorter. Change scratch1 to be length of right string.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003755 __ sub(scratch1, length_delta);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003756 __ bind(&left_shorter);
3757
3758 Register min_length = scratch1;
3759
3760 // If either length is zero, just compare lengths.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003761 Label compare_lengths;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003762 __ test(min_length, min_length);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003763 __ j(zero, &compare_lengths, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003764
lrn@chromium.org1c092762011-05-09 09:42:16 +00003765 // Compare characters.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003766 Label result_not_equal;
lrn@chromium.org1c092762011-05-09 09:42:16 +00003767 GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2,
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003768 &result_not_equal, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003769
3770 // Compare lengths - strings up to min-length are equal.
3771 __ bind(&compare_lengths);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003772 __ test(length_delta, length_delta);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003773 Label length_not_equal;
3774 __ j(not_zero, &length_not_equal, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003775
3776 // Result is EQUAL.
3777 STATIC_ASSERT(EQUAL == 0);
3778 STATIC_ASSERT(kSmiTag == 0);
3779 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
3780 __ ret(0);
3781
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003782 Label result_greater;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003783 Label result_less;
3784 __ bind(&length_not_equal);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003785 __ j(greater, &result_greater, Label::kNear);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003786 __ jmp(&result_less, Label::kNear);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003787 __ bind(&result_not_equal);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003788 __ j(above, &result_greater, Label::kNear);
3789 __ bind(&result_less);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003790
3791 // Result is LESS.
3792 __ Set(eax, Immediate(Smi::FromInt(LESS)));
3793 __ ret(0);
3794
3795 // Result is GREATER.
3796 __ bind(&result_greater);
3797 __ Set(eax, Immediate(Smi::FromInt(GREATER)));
3798 __ ret(0);
3799}
3800
3801
lrn@chromium.org1c092762011-05-09 09:42:16 +00003802void StringCompareStub::GenerateAsciiCharsCompareLoop(
3803 MacroAssembler* masm,
3804 Register left,
3805 Register right,
3806 Register length,
3807 Register scratch,
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003808 Label* chars_not_equal,
3809 Label::Distance chars_not_equal_near) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00003810 // Change index to run from -length to -1 by adding length to string
3811 // start. This means that loop ends when index reaches zero, which
3812 // doesn't need an additional compare.
3813 __ SmiUntag(length);
3814 __ lea(left,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003815 FieldOperand(left, length, times_1, SeqOneByteString::kHeaderSize));
lrn@chromium.org1c092762011-05-09 09:42:16 +00003816 __ lea(right,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003817 FieldOperand(right, length, times_1, SeqOneByteString::kHeaderSize));
lrn@chromium.org1c092762011-05-09 09:42:16 +00003818 __ neg(length);
3819 Register index = length; // index = -length;
3820
3821 // Compare loop.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003822 Label loop;
lrn@chromium.org1c092762011-05-09 09:42:16 +00003823 __ bind(&loop);
3824 __ mov_b(scratch, Operand(left, index, times_1, 0));
3825 __ cmpb(scratch, Operand(right, index, times_1, 0));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003826 __ j(not_equal, chars_not_equal, chars_not_equal_near);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003827 __ inc(index);
lrn@chromium.org1c092762011-05-09 09:42:16 +00003828 __ j(not_zero, &loop);
3829}
3830
3831
ricow@chromium.org65fae842010-08-25 15:26:24 +00003832void StringCompareStub::Generate(MacroAssembler* masm) {
3833 Label runtime;
3834
3835 // Stack frame on entry.
3836 // esp[0]: return address
3837 // esp[4]: right string
3838 // esp[8]: left string
3839
3840 __ mov(edx, Operand(esp, 2 * kPointerSize)); // left
3841 __ mov(eax, Operand(esp, 1 * kPointerSize)); // right
3842
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003843 Label not_same;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003844 __ cmp(edx, eax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003845 __ j(not_equal, &not_same, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003846 STATIC_ASSERT(EQUAL == 0);
3847 STATIC_ASSERT(kSmiTag == 0);
3848 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003849 __ IncrementCounter(masm->isolate()->counters()->string_compare_native(), 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003850 __ ret(2 * kPointerSize);
3851
3852 __ bind(&not_same);
3853
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003854 // Check that both objects are sequential ASCII strings.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003855 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime);
3856
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003857 // Compare flat ASCII strings.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003858 // Drop arguments from the stack.
3859 __ pop(ecx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003860 __ add(esp, Immediate(2 * kPointerSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003861 __ push(ecx);
3862 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi);
3863
3864 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
3865 // tagged as a small integer.
3866 __ bind(&runtime);
3867 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
3868}
3869
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003870
machenbach@chromium.orgc8cbc432014-01-21 09:01:57 +00003871void ArrayPushStub::Generate(MacroAssembler* masm) {
3872 int argc = arguments_count();
3873
3874 if (argc == 0) {
3875 // Noop, return the length.
3876 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
3877 __ ret((argc + 1) * kPointerSize);
3878 return;
3879 }
3880
3881 Isolate* isolate = masm->isolate();
3882
3883 if (argc != 1) {
3884 __ TailCallExternalReference(
3885 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
3886 return;
3887 }
3888
3889 Label call_builtin, attempt_to_grow_elements, with_write_barrier;
3890
3891 // Get the elements array of the object.
3892 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
3893
3894 if (IsFastSmiOrObjectElementsKind(elements_kind())) {
3895 // Check that the elements are in fast mode and writable.
3896 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
3897 isolate->factory()->fixed_array_map());
3898 __ j(not_equal, &call_builtin);
3899 }
3900
3901 // Get the array's length into eax and calculate new length.
3902 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
3903 STATIC_ASSERT(kSmiTagSize == 1);
3904 STATIC_ASSERT(kSmiTag == 0);
3905 __ add(eax, Immediate(Smi::FromInt(argc)));
3906
3907 // Get the elements' length into ecx.
3908 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
3909
3910 // Check if we could survive without allocation.
3911 __ cmp(eax, ecx);
3912
3913 if (IsFastSmiOrObjectElementsKind(elements_kind())) {
3914 __ j(greater, &attempt_to_grow_elements);
3915
3916 // Check if value is a smi.
3917 __ mov(ecx, Operand(esp, argc * kPointerSize));
3918 __ JumpIfNotSmi(ecx, &with_write_barrier);
3919
3920 // Store the value.
3921 __ mov(FieldOperand(edi, eax, times_half_pointer_size,
3922 FixedArray::kHeaderSize - argc * kPointerSize),
3923 ecx);
3924 } else {
3925 __ j(greater, &call_builtin);
3926
3927 __ mov(ecx, Operand(esp, argc * kPointerSize));
3928 __ StoreNumberToDoubleElements(
3929 ecx, edi, eax, ecx, xmm0, &call_builtin, true, argc * kDoubleSize);
3930 }
3931
3932 // Save new length.
3933 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
3934 __ ret((argc + 1) * kPointerSize);
3935
3936 if (IsFastDoubleElementsKind(elements_kind())) {
3937 __ bind(&call_builtin);
3938 __ TailCallExternalReference(
3939 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
3940 return;
3941 }
3942
3943 __ bind(&with_write_barrier);
3944
3945 if (IsFastSmiElementsKind(elements_kind())) {
3946 if (FLAG_trace_elements_transitions) __ jmp(&call_builtin);
3947
3948 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
3949 isolate->factory()->heap_number_map());
3950 __ j(equal, &call_builtin);
3951
3952 ElementsKind target_kind = IsHoleyElementsKind(elements_kind())
3953 ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS;
3954 __ mov(ebx, ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX));
3955 __ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
3956 __ mov(ebx, ContextOperand(ebx, Context::JS_ARRAY_MAPS_INDEX));
3957 const int header_size = FixedArrayBase::kHeaderSize;
3958 // Verify that the object can be transitioned in place.
3959 const int origin_offset = header_size + elements_kind() * kPointerSize;
3960 __ mov(edi, FieldOperand(ebx, origin_offset));
3961 __ cmp(edi, FieldOperand(edx, HeapObject::kMapOffset));
3962 __ j(not_equal, &call_builtin);
3963
3964 const int target_offset = header_size + target_kind * kPointerSize;
3965 __ mov(ebx, FieldOperand(ebx, target_offset));
3966 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
3967 masm, DONT_TRACK_ALLOCATION_SITE, NULL);
3968 // Restore edi used as a scratch register for the write barrier used while
3969 // setting the map.
3970 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
3971 }
3972
3973 // Save new length.
3974 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
3975
3976 // Store the value.
3977 __ lea(edx, FieldOperand(edi, eax, times_half_pointer_size,
3978 FixedArray::kHeaderSize - argc * kPointerSize));
3979 __ mov(Operand(edx, 0), ecx);
3980
3981 __ RecordWrite(edi, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
3982 OMIT_SMI_CHECK);
3983
3984 __ ret((argc + 1) * kPointerSize);
3985
3986 __ bind(&attempt_to_grow_elements);
3987 if (!FLAG_inline_new) {
3988 __ bind(&call_builtin);
3989 __ TailCallExternalReference(
3990 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
3991 return;
3992 }
3993
3994 __ mov(ebx, Operand(esp, argc * kPointerSize));
3995 // Growing elements that are SMI-only requires special handling in case the
3996 // new element is non-Smi. For now, delegate to the builtin.
3997 if (IsFastSmiElementsKind(elements_kind())) {
3998 __ JumpIfNotSmi(ebx, &call_builtin);
3999 }
4000
4001 // We could be lucky and the elements array could be at the top of new-space.
4002 // In this case we can just grow it in place by moving the allocation pointer
4003 // up.
4004 ExternalReference new_space_allocation_top =
4005 ExternalReference::new_space_allocation_top_address(isolate);
4006 ExternalReference new_space_allocation_limit =
4007 ExternalReference::new_space_allocation_limit_address(isolate);
4008
4009 const int kAllocationDelta = 4;
4010 ASSERT(kAllocationDelta >= argc);
4011 // Load top.
4012 __ mov(ecx, Operand::StaticVariable(new_space_allocation_top));
4013
4014 // Check if it's the end of elements.
4015 __ lea(edx, FieldOperand(edi, eax, times_half_pointer_size,
4016 FixedArray::kHeaderSize - argc * kPointerSize));
4017 __ cmp(edx, ecx);
4018 __ j(not_equal, &call_builtin);
4019 __ add(ecx, Immediate(kAllocationDelta * kPointerSize));
4020 __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit));
4021 __ j(above, &call_builtin);
4022
4023 // We fit and could grow elements.
4024 __ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
4025
4026 // Push the argument...
4027 __ mov(Operand(edx, 0), ebx);
4028 // ... and fill the rest with holes.
4029 for (int i = 1; i < kAllocationDelta; i++) {
4030 __ mov(Operand(edx, i * kPointerSize),
4031 isolate->factory()->the_hole_value());
4032 }
4033
4034 if (IsFastObjectElementsKind(elements_kind())) {
4035 // We know the elements array is in new space so we don't need the
4036 // remembered set, but we just pushed a value onto it so we may have to tell
4037 // the incremental marker to rescan the object that we just grew. We don't
4038 // need to worry about the holes because they are in old space and already
4039 // marked black.
4040 __ RecordWrite(edi, edx, ebx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
4041 }
4042
4043 // Restore receiver to edx as finish sequence assumes it's here.
4044 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
4045
4046 // Increment element's and array's sizes.
4047 __ add(FieldOperand(edi, FixedArray::kLengthOffset),
4048 Immediate(Smi::FromInt(kAllocationDelta)));
4049
4050 // NOTE: This only happen in new-space, where we don't care about the
4051 // black-byte-count on pages. Otherwise we should update that too if the
4052 // object is black.
4053
4054 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
4055 __ ret((argc + 1) * kPointerSize);
4056
4057 __ bind(&call_builtin);
4058 __ TailCallExternalReference(
4059 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
4060}
4061
4062
ulan@chromium.org0f13e742014-01-03 15:51:11 +00004063void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
4064 // ----------- S t a t e -------------
4065 // -- edx : left
4066 // -- eax : right
4067 // -- esp[0] : return address
4068 // -----------------------------------
4069 Isolate* isolate = masm->isolate();
4070
4071 // Load ecx with the allocation site. We stick an undefined dummy value here
4072 // and replace it with the real allocation site later when we instantiate this
4073 // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
4074 __ mov(ecx, handle(isolate->heap()->undefined_value()));
4075
4076 // Make sure that we actually patched the allocation site.
4077 if (FLAG_debug_code) {
4078 __ test(ecx, Immediate(kSmiTagMask));
4079 __ Assert(not_equal, kExpectedAllocationSite);
4080 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
4081 isolate->factory()->allocation_site_map());
4082 __ Assert(equal, kExpectedAllocationSite);
4083 }
4084
4085 // Tail call into the stub that handles binary operations with allocation
4086 // sites.
4087 BinaryOpWithAllocationSiteStub stub(state_);
4088 __ TailCallStub(&stub);
4089}
4090
4091
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004092void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004093 ASSERT(state_ == CompareIC::SMI);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004094 Label miss;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004095 __ mov(ecx, edx);
4096 __ or_(ecx, eax);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004097 __ JumpIfNotSmi(ecx, &miss, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004098
4099 if (GetCondition() == equal) {
4100 // For equality we do not care about the sign of the result.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004101 __ sub(eax, edx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004102 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004103 Label done;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004104 __ sub(edx, eax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004105 __ j(no_overflow, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004106 // Correct sign of result in case of overflow.
4107 __ not_(edx);
4108 __ bind(&done);
4109 __ mov(eax, edx);
4110 }
4111 __ ret(0);
4112
4113 __ bind(&miss);
4114 GenerateMiss(masm);
4115}
4116
4117
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004118void ICCompareStub::GenerateNumbers(MacroAssembler* masm) {
4119 ASSERT(state_ == CompareIC::NUMBER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004120
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004121 Label generic_stub;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004122 Label unordered, maybe_undefined1, maybe_undefined2;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004123 Label miss;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004124
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004125 if (left_ == CompareIC::SMI) {
4126 __ JumpIfNotSmi(edx, &miss);
4127 }
4128 if (right_ == CompareIC::SMI) {
4129 __ JumpIfNotSmi(eax, &miss);
4130 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004131
4132 // Inlining the double comparison and falling back to the general compare
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004133 // stub if NaN is involved or SSE2 or CMOV is unsupported.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004134 if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004135 CpuFeatureScope scope1(masm, SSE2);
4136 CpuFeatureScope scope2(masm, CMOV);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004137
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004138 // Load left and right operand.
4139 Label done, left, left_smi, right_smi;
4140 __ JumpIfSmi(eax, &right_smi, Label::kNear);
4141 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
4142 masm->isolate()->factory()->heap_number_map());
4143 __ j(not_equal, &maybe_undefined1, Label::kNear);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004144 __ movsd(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004145 __ jmp(&left, Label::kNear);
4146 __ bind(&right_smi);
4147 __ mov(ecx, eax); // Can't clobber eax because we can still jump away.
4148 __ SmiUntag(ecx);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004149 __ Cvtsi2sd(xmm1, ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004150
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004151 __ bind(&left);
4152 __ JumpIfSmi(edx, &left_smi, Label::kNear);
4153 __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
4154 masm->isolate()->factory()->heap_number_map());
4155 __ j(not_equal, &maybe_undefined2, Label::kNear);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004156 __ movsd(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004157 __ jmp(&done);
4158 __ bind(&left_smi);
4159 __ mov(ecx, edx); // Can't clobber edx because we can still jump away.
4160 __ SmiUntag(ecx);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004161 __ Cvtsi2sd(xmm0, ecx);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004162
4163 __ bind(&done);
4164 // Compare operands.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004165 __ ucomisd(xmm0, xmm1);
4166
4167 // Don't base result on EFLAGS when a NaN is involved.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004168 __ j(parity_even, &unordered, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004169
4170 // Return a result of -1, 0, or 1, based on EFLAGS.
4171 // Performing mov, because xor would destroy the flag register.
4172 __ mov(eax, 0); // equal
4173 __ mov(ecx, Immediate(Smi::FromInt(1)));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004174 __ cmov(above, eax, ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004175 __ mov(ecx, Immediate(Smi::FromInt(-1)));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004176 __ cmov(below, eax, ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004177 __ ret(0);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004178 } else {
4179 __ mov(ecx, edx);
4180 __ and_(ecx, eax);
4181 __ JumpIfSmi(ecx, &generic_stub, Label::kNear);
4182
4183 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
4184 masm->isolate()->factory()->heap_number_map());
4185 __ j(not_equal, &maybe_undefined1, Label::kNear);
4186 __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
4187 masm->isolate()->factory()->heap_number_map());
4188 __ j(not_equal, &maybe_undefined2, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004189 }
4190
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004191 __ bind(&unordered);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004192 __ bind(&generic_stub);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004193 ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC,
4194 CompareIC::GENERIC);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004195 __ jmp(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004196
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004197 __ bind(&maybe_undefined1);
4198 if (Token::IsOrderedRelationalCompareOp(op_)) {
4199 __ cmp(eax, Immediate(masm->isolate()->factory()->undefined_value()));
4200 __ j(not_equal, &miss);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004201 __ JumpIfSmi(edx, &unordered);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004202 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
4203 __ j(not_equal, &maybe_undefined2, Label::kNear);
4204 __ jmp(&unordered);
4205 }
4206
4207 __ bind(&maybe_undefined2);
4208 if (Token::IsOrderedRelationalCompareOp(op_)) {
4209 __ cmp(edx, Immediate(masm->isolate()->factory()->undefined_value()));
4210 __ j(equal, &unordered);
4211 }
4212
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004213 __ bind(&miss);
4214 GenerateMiss(masm);
4215}
4216
4217
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004218void ICCompareStub::GenerateInternalizedStrings(MacroAssembler* masm) {
4219 ASSERT(state_ == CompareIC::INTERNALIZED_STRING);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004220 ASSERT(GetCondition() == equal);
4221
4222 // Registers containing left and right operands respectively.
4223 Register left = edx;
4224 Register right = eax;
4225 Register tmp1 = ecx;
4226 Register tmp2 = ebx;
4227
4228 // Check that both operands are heap objects.
4229 Label miss;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004230 __ mov(tmp1, left);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004231 STATIC_ASSERT(kSmiTag == 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004232 __ and_(tmp1, right);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004233 __ JumpIfSmi(tmp1, &miss, Label::kNear);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004234
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004235 // Check that both operands are internalized strings.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004236 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
4237 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
4238 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
4239 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004240 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
4241 __ or_(tmp1, tmp2);
4242 __ test(tmp1, Immediate(kIsNotStringMask | kIsNotInternalizedMask));
4243 __ j(not_zero, &miss, Label::kNear);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004244
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004245 // Internalized strings are compared by identity.
4246 Label done;
4247 __ cmp(left, right);
4248 // Make sure eax is non-zero. At this point input operands are
4249 // guaranteed to be non-zero.
4250 ASSERT(right.is(eax));
4251 __ j(not_equal, &done, Label::kNear);
4252 STATIC_ASSERT(EQUAL == 0);
4253 STATIC_ASSERT(kSmiTag == 0);
4254 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
4255 __ bind(&done);
4256 __ ret(0);
4257
4258 __ bind(&miss);
4259 GenerateMiss(masm);
4260}
4261
4262
4263void ICCompareStub::GenerateUniqueNames(MacroAssembler* masm) {
4264 ASSERT(state_ == CompareIC::UNIQUE_NAME);
4265 ASSERT(GetCondition() == equal);
4266
4267 // Registers containing left and right operands respectively.
4268 Register left = edx;
4269 Register right = eax;
4270 Register tmp1 = ecx;
4271 Register tmp2 = ebx;
4272
4273 // Check that both operands are heap objects.
4274 Label miss;
4275 __ mov(tmp1, left);
4276 STATIC_ASSERT(kSmiTag == 0);
4277 __ and_(tmp1, right);
4278 __ JumpIfSmi(tmp1, &miss, Label::kNear);
4279
4280 // Check that both operands are unique names. This leaves the instance
4281 // types loaded in tmp1 and tmp2.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004282 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
4283 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
4284 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
4285 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
4286
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004287 __ JumpIfNotUniqueName(tmp1, &miss, Label::kNear);
4288 __ JumpIfNotUniqueName(tmp2, &miss, Label::kNear);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004289
4290 // Unique names are compared by identity.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004291 Label done;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004292 __ cmp(left, right);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004293 // Make sure eax is non-zero. At this point input operands are
4294 // guaranteed to be non-zero.
4295 ASSERT(right.is(eax));
4296 __ j(not_equal, &done, Label::kNear);
4297 STATIC_ASSERT(EQUAL == 0);
4298 STATIC_ASSERT(kSmiTag == 0);
4299 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
4300 __ bind(&done);
4301 __ ret(0);
4302
4303 __ bind(&miss);
4304 GenerateMiss(masm);
4305}
4306
4307
lrn@chromium.org1c092762011-05-09 09:42:16 +00004308void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004309 ASSERT(state_ == CompareIC::STRING);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004310 Label miss;
4311
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004312 bool equality = Token::IsEqualityOp(op_);
4313
lrn@chromium.org1c092762011-05-09 09:42:16 +00004314 // Registers containing left and right operands respectively.
4315 Register left = edx;
4316 Register right = eax;
4317 Register tmp1 = ecx;
4318 Register tmp2 = ebx;
4319 Register tmp3 = edi;
4320
4321 // Check that both operands are heap objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004322 __ mov(tmp1, left);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004323 STATIC_ASSERT(kSmiTag == 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004324 __ and_(tmp1, right);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004325 __ JumpIfSmi(tmp1, &miss);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004326
4327 // Check that both operands are strings. This leaves the instance
4328 // types loaded in tmp1 and tmp2.
4329 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
4330 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
4331 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
4332 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
4333 __ mov(tmp3, tmp1);
4334 STATIC_ASSERT(kNotStringTag != 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004335 __ or_(tmp3, tmp2);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004336 __ test(tmp3, Immediate(kIsNotStringMask));
4337 __ j(not_zero, &miss);
4338
4339 // Fast check for identical strings.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004340 Label not_same;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004341 __ cmp(left, right);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004342 __ j(not_equal, &not_same, Label::kNear);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004343 STATIC_ASSERT(EQUAL == 0);
4344 STATIC_ASSERT(kSmiTag == 0);
4345 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
4346 __ ret(0);
4347
4348 // Handle not identical strings.
4349 __ bind(&not_same);
4350
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004351 // Check that both strings are internalized. If they are, we're done
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004352 // because we already know they are not identical. But in the case of
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004353 // non-equality compare, we still need to determine the order. We
4354 // also know they are both strings.
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004355 if (equality) {
4356 Label do_compare;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004357 STATIC_ASSERT(kInternalizedTag == 0);
4358 __ or_(tmp1, tmp2);
4359 __ test(tmp1, Immediate(kIsNotInternalizedMask));
4360 __ j(not_zero, &do_compare, Label::kNear);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004361 // Make sure eax is non-zero. At this point input operands are
4362 // guaranteed to be non-zero.
4363 ASSERT(right.is(eax));
4364 __ ret(0);
4365 __ bind(&do_compare);
4366 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00004367
4368 // Check that both strings are sequential ASCII.
4369 Label runtime;
lrn@chromium.org1c092762011-05-09 09:42:16 +00004370 __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime);
4371
4372 // Compare flat ASCII strings. Returns when done.
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004373 if (equality) {
4374 StringCompareStub::GenerateFlatAsciiStringEquals(
4375 masm, left, right, tmp1, tmp2);
4376 } else {
4377 StringCompareStub::GenerateCompareFlatAsciiStrings(
4378 masm, left, right, tmp1, tmp2, tmp3);
4379 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00004380
4381 // Handle more complex cases in runtime.
4382 __ bind(&runtime);
4383 __ pop(tmp1); // Return address.
4384 __ push(left);
4385 __ push(right);
4386 __ push(tmp1);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004387 if (equality) {
4388 __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
4389 } else {
4390 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
4391 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00004392
4393 __ bind(&miss);
4394 GenerateMiss(masm);
4395}
4396
4397
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004398void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004399 ASSERT(state_ == CompareIC::OBJECT);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004400 Label miss;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004401 __ mov(ecx, edx);
4402 __ and_(ecx, eax);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004403 __ JumpIfSmi(ecx, &miss, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004404
4405 __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004406 __ j(not_equal, &miss, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004407 __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004408 __ j(not_equal, &miss, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004409
4410 ASSERT(GetCondition() == equal);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004411 __ sub(eax, edx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004412 __ ret(0);
4413
4414 __ bind(&miss);
4415 GenerateMiss(masm);
4416}
4417
4418
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004419void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
4420 Label miss;
4421 __ mov(ecx, edx);
4422 __ and_(ecx, eax);
4423 __ JumpIfSmi(ecx, &miss, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004424
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004425 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
4426 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
4427 __ cmp(ecx, known_map_);
4428 __ j(not_equal, &miss, Label::kNear);
4429 __ cmp(ebx, known_map_);
4430 __ j(not_equal, &miss, Label::kNear);
4431
4432 __ sub(eax, edx);
4433 __ ret(0);
4434
4435 __ bind(&miss);
4436 GenerateMiss(masm);
4437}
4438
4439
4440void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004441 {
4442 // Call the runtime system in a fresh internal frame.
4443 ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss),
4444 masm->isolate());
4445 FrameScope scope(masm, StackFrame::INTERNAL);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004446 __ push(edx); // Preserve edx and eax.
4447 __ push(eax);
4448 __ push(edx); // And also use them as the arguments.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004449 __ push(eax);
4450 __ push(Immediate(Smi::FromInt(op_)));
4451 __ CallExternalReference(miss, 3);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004452 // Compute the entry point of the rewritten stub.
4453 __ lea(edi, FieldOperand(eax, Code::kHeaderSize));
4454 __ pop(eax);
4455 __ pop(edx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004456 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004457
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004458 // Do a tail call to the rewritten stub.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004459 __ jmp(edi);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004460}
4461
4462
lrn@chromium.org1c092762011-05-09 09:42:16 +00004463// Helper function used to check that the dictionary doesn't contain
4464// the property. This function may return false negatives, so miss_label
4465// must always call a backup property check that is complete.
4466// This function is safe to call if the receiver has fast properties.
ulan@chromium.org750145a2013-03-07 15:14:13 +00004467// Name must be a unique name and receiver must be a heap object.
4468void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
4469 Label* miss,
4470 Label* done,
4471 Register properties,
4472 Handle<Name> name,
4473 Register r0) {
4474 ASSERT(name->IsUniqueName());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004475
4476 // If names of slots in range from 1 to kProbes - 1 for the hash value are
4477 // not equal to the name and kProbes-th slot is not used (its name is the
4478 // undefined value), it guarantees the hash table doesn't contain the
4479 // property. It's true even if some slots represent deleted properties
ulan@chromium.org967e2702012-02-28 09:49:15 +00004480 // (their names are the hole value).
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004481 for (int i = 0; i < kInlinedProbes; i++) {
4482 // Compute the masked index: (hash + i + i * i) & mask.
4483 Register index = r0;
4484 // Capacity is smi 2^n.
4485 __ mov(index, FieldOperand(properties, kCapacityOffset));
4486 __ dec(index);
4487 __ and_(index,
4488 Immediate(Smi::FromInt(name->Hash() +
ulan@chromium.org750145a2013-03-07 15:14:13 +00004489 NameDictionary::GetProbeOffset(i))));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004490
4491 // Scale the index by multiplying by the entry size.
ulan@chromium.org750145a2013-03-07 15:14:13 +00004492 ASSERT(NameDictionary::kEntrySize == 3);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004493 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3.
4494 Register entity_name = r0;
4495 // Having undefined at this place means the name is not contained.
4496 ASSERT_EQ(kSmiTagSize, 1);
4497 __ mov(entity_name, Operand(properties, index, times_half_pointer_size,
4498 kElementsStartOffset - kHeapObjectTag));
4499 __ cmp(entity_name, masm->isolate()->factory()->undefined_value());
4500 __ j(equal, done);
4501
4502 // Stop if found the property.
ulan@chromium.org750145a2013-03-07 15:14:13 +00004503 __ cmp(entity_name, Handle<Name>(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004504 __ j(equal, miss);
4505
ulan@chromium.org750145a2013-03-07 15:14:13 +00004506 Label good;
ulan@chromium.org967e2702012-02-28 09:49:15 +00004507 // Check for the hole and skip.
4508 __ cmp(entity_name, masm->isolate()->factory()->the_hole_value());
ulan@chromium.org750145a2013-03-07 15:14:13 +00004509 __ j(equal, &good, Label::kNear);
ulan@chromium.org967e2702012-02-28 09:49:15 +00004510
ulan@chromium.org750145a2013-03-07 15:14:13 +00004511 // Check if the entry name is not a unique name.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004512 __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004513 __ JumpIfNotUniqueName(FieldOperand(entity_name, Map::kInstanceTypeOffset),
4514 miss);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004515 __ bind(&good);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004516 }
4517
ulan@chromium.org750145a2013-03-07 15:14:13 +00004518 NameDictionaryLookupStub stub(properties, r0, r0, NEGATIVE_LOOKUP);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004519 __ push(Immediate(Handle<Object>(name)));
4520 __ push(Immediate(name->Hash()));
4521 __ CallStub(&stub);
4522 __ test(r0, r0);
4523 __ j(not_zero, miss);
4524 __ jmp(done);
4525}
4526
4527
ulan@chromium.org750145a2013-03-07 15:14:13 +00004528// Probe the name dictionary in the |elements| register. Jump to the
lrn@chromium.org1c092762011-05-09 09:42:16 +00004529// |done| label if a property with the given name is found leaving the
4530// index into the dictionary in |r0|. Jump to the |miss| label
4531// otherwise.
ulan@chromium.org750145a2013-03-07 15:14:13 +00004532void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
4533 Label* miss,
4534 Label* done,
4535 Register elements,
4536 Register name,
4537 Register r0,
4538 Register r1) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00004539 ASSERT(!elements.is(r0));
4540 ASSERT(!elements.is(r1));
4541 ASSERT(!name.is(r0));
4542 ASSERT(!name.is(r1));
4543
ulan@chromium.org750145a2013-03-07 15:14:13 +00004544 __ AssertName(name);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004545
4546 __ mov(r1, FieldOperand(elements, kCapacityOffset));
4547 __ shr(r1, kSmiTagSize); // convert smi to int
4548 __ dec(r1);
4549
4550 // Generate an unrolled loop that performs a few probes before
4551 // giving up. Measurements done on Gmail indicate that 2 probes
4552 // cover ~93% of loads from dictionaries.
4553 for (int i = 0; i < kInlinedProbes; i++) {
4554 // Compute the masked index: (hash + i + i * i) & mask.
ulan@chromium.org750145a2013-03-07 15:14:13 +00004555 __ mov(r0, FieldOperand(name, Name::kHashFieldOffset));
4556 __ shr(r0, Name::kHashShift);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004557 if (i > 0) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004558 __ add(r0, Immediate(NameDictionary::GetProbeOffset(i)));
lrn@chromium.org1c092762011-05-09 09:42:16 +00004559 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004560 __ and_(r0, r1);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004561
4562 // Scale the index by multiplying by the entry size.
ulan@chromium.org750145a2013-03-07 15:14:13 +00004563 ASSERT(NameDictionary::kEntrySize == 3);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004564 __ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3
4565
4566 // Check if the key is identical to the name.
4567 __ cmp(name, Operand(elements,
4568 r0,
4569 times_4,
4570 kElementsStartOffset - kHeapObjectTag));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004571 __ j(equal, done);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004572 }
4573
ulan@chromium.org750145a2013-03-07 15:14:13 +00004574 NameDictionaryLookupStub stub(elements, r1, r0, POSITIVE_LOOKUP);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004575 __ push(name);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004576 __ mov(r0, FieldOperand(name, Name::kHashFieldOffset));
4577 __ shr(r0, Name::kHashShift);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004578 __ push(r0);
4579 __ CallStub(&stub);
4580
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004581 __ test(r1, r1);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004582 __ j(zero, miss);
4583 __ jmp(done);
4584}
4585
4586
ulan@chromium.org750145a2013-03-07 15:14:13 +00004587void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004588 // This stub overrides SometimesSetsUpAFrame() to return false. That means
4589 // we cannot call anything that could cause a GC from this stub.
lrn@chromium.org1c092762011-05-09 09:42:16 +00004590 // Stack frame on entry:
4591 // esp[0 * kPointerSize]: return address.
4592 // esp[1 * kPointerSize]: key's hash.
4593 // esp[2 * kPointerSize]: key.
4594 // Registers:
ulan@chromium.org750145a2013-03-07 15:14:13 +00004595 // dictionary_: NameDictionary to probe.
lrn@chromium.org1c092762011-05-09 09:42:16 +00004596 // result_: used as scratch.
4597 // index_: will hold an index of entry if lookup is successful.
4598 // might alias with result_.
4599 // Returns:
4600 // result_ is zero if lookup failed, non zero otherwise.
4601
4602 Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
4603
4604 Register scratch = result_;
4605
4606 __ mov(scratch, FieldOperand(dictionary_, kCapacityOffset));
4607 __ dec(scratch);
4608 __ SmiUntag(scratch);
4609 __ push(scratch);
4610
4611 // If names of slots in range from 1 to kProbes - 1 for the hash value are
4612 // not equal to the name and kProbes-th slot is not used (its name is the
4613 // undefined value), it guarantees the hash table doesn't contain the
4614 // property. It's true even if some slots represent deleted properties
4615 // (their names are the null value).
4616 for (int i = kInlinedProbes; i < kTotalProbes; i++) {
4617 // Compute the masked index: (hash + i + i * i) & mask.
4618 __ mov(scratch, Operand(esp, 2 * kPointerSize));
4619 if (i > 0) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004620 __ add(scratch, Immediate(NameDictionary::GetProbeOffset(i)));
lrn@chromium.org1c092762011-05-09 09:42:16 +00004621 }
4622 __ and_(scratch, Operand(esp, 0));
4623
4624 // Scale the index by multiplying by the entry size.
ulan@chromium.org750145a2013-03-07 15:14:13 +00004625 ASSERT(NameDictionary::kEntrySize == 3);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004626 __ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3.
4627
4628 // Having undefined at this place means the name is not contained.
4629 ASSERT_EQ(kSmiTagSize, 1);
4630 __ mov(scratch, Operand(dictionary_,
4631 index_,
4632 times_pointer_size,
4633 kElementsStartOffset - kHeapObjectTag));
4634 __ cmp(scratch, masm->isolate()->factory()->undefined_value());
4635 __ j(equal, &not_in_dictionary);
4636
4637 // Stop if found the property.
4638 __ cmp(scratch, Operand(esp, 3 * kPointerSize));
4639 __ j(equal, &in_dictionary);
4640
4641 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004642 // If we hit a key that is not a unique name during negative
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004643 // lookup we have to bailout as this key might be equal to the
lrn@chromium.org1c092762011-05-09 09:42:16 +00004644 // key we are looking for.
4645
ulan@chromium.org750145a2013-03-07 15:14:13 +00004646 // Check if the entry name is not a unique name.
lrn@chromium.org1c092762011-05-09 09:42:16 +00004647 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004648 __ JumpIfNotUniqueName(FieldOperand(scratch, Map::kInstanceTypeOffset),
4649 &maybe_in_dictionary);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004650 }
4651 }
4652
4653 __ bind(&maybe_in_dictionary);
4654 // If we are doing negative lookup then probing failure should be
4655 // treated as a lookup success. For positive lookup probing failure
4656 // should be treated as lookup failure.
4657 if (mode_ == POSITIVE_LOOKUP) {
4658 __ mov(result_, Immediate(0));
4659 __ Drop(1);
4660 __ ret(2 * kPointerSize);
4661 }
4662
4663 __ bind(&in_dictionary);
4664 __ mov(result_, Immediate(1));
4665 __ Drop(1);
4666 __ ret(2 * kPointerSize);
4667
4668 __ bind(&not_in_dictionary);
4669 __ mov(result_, Immediate(0));
4670 __ Drop(1);
4671 __ ret(2 * kPointerSize);
4672}
4673
4674
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004675void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
4676 Isolate* isolate) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004677 StoreBufferOverflowStub stub(kDontSaveFPRegs);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00004678 stub.GetCode(isolate);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004679 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004680 StoreBufferOverflowStub stub2(kSaveFPRegs);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00004681 stub2.GetCode(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004682 }
4683}
4684
4685
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004686bool CodeStub::CanUseFPRegisters() {
4687 return CpuFeatures::IsSupported(SSE2);
4688}
4689
4690
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004691// Takes the input in 3 registers: address_ value_ and object_. A pointer to
4692// the value has just been written into the object, now this stub makes sure
4693// we keep the GC informed. The word in the object where the value has been
4694// written is in the address register.
4695void RecordWriteStub::Generate(MacroAssembler* masm) {
4696 Label skip_to_incremental_noncompacting;
4697 Label skip_to_incremental_compacting;
4698
4699 // The first two instructions are generated with labels so as to get the
4700 // offset fixed up correctly by the bind(Label*) call. We patch it back and
4701 // forth between a compare instructions (a nop in this position) and the
4702 // real branch when we start and stop incremental heap marking.
4703 __ jmp(&skip_to_incremental_noncompacting, Label::kNear);
4704 __ jmp(&skip_to_incremental_compacting, Label::kFar);
4705
4706 if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
4707 __ RememberedSetHelper(object_,
4708 address_,
4709 value_,
4710 save_fp_regs_mode_,
4711 MacroAssembler::kReturnAtEnd);
4712 } else {
4713 __ ret(0);
4714 }
4715
4716 __ bind(&skip_to_incremental_noncompacting);
4717 GenerateIncremental(masm, INCREMENTAL);
4718
4719 __ bind(&skip_to_incremental_compacting);
4720 GenerateIncremental(masm, INCREMENTAL_COMPACTION);
4721
4722 // Initial mode of the stub is expected to be STORE_BUFFER_ONLY.
4723 // Will be checked in IncrementalMarking::ActivateGeneratedStub.
4724 masm->set_byte_at(0, kTwoByteNopInstruction);
4725 masm->set_byte_at(2, kFiveByteNopInstruction);
4726}
4727
4728
4729void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
4730 regs_.Save(masm);
4731
4732 if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
4733 Label dont_need_remembered_set;
4734
4735 __ mov(regs_.scratch0(), Operand(regs_.address(), 0));
4736 __ JumpIfNotInNewSpace(regs_.scratch0(), // Value.
4737 regs_.scratch0(),
4738 &dont_need_remembered_set);
4739
4740 __ CheckPageFlag(regs_.object(),
4741 regs_.scratch0(),
4742 1 << MemoryChunk::SCAN_ON_SCAVENGE,
4743 not_zero,
4744 &dont_need_remembered_set);
4745
4746 // First notify the incremental marker if necessary, then update the
4747 // remembered set.
4748 CheckNeedsToInformIncrementalMarker(
4749 masm,
4750 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker,
4751 mode);
4752 InformIncrementalMarker(masm, mode);
4753 regs_.Restore(masm);
4754 __ RememberedSetHelper(object_,
4755 address_,
4756 value_,
4757 save_fp_regs_mode_,
4758 MacroAssembler::kReturnAtEnd);
4759
4760 __ bind(&dont_need_remembered_set);
4761 }
4762
4763 CheckNeedsToInformIncrementalMarker(
4764 masm,
4765 kReturnOnNoNeedToInformIncrementalMarker,
4766 mode);
4767 InformIncrementalMarker(masm, mode);
4768 regs_.Restore(masm);
4769 __ ret(0);
4770}
4771
4772
4773void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) {
4774 regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_);
4775 int argument_count = 3;
4776 __ PrepareCallCFunction(argument_count, regs_.scratch0());
4777 __ mov(Operand(esp, 0 * kPointerSize), regs_.object());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004778 __ mov(Operand(esp, 1 * kPointerSize), regs_.address()); // Slot.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004779 __ mov(Operand(esp, 2 * kPointerSize),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004780 Immediate(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004781
4782 AllowExternalCallThatCantCauseGC scope(masm);
4783 if (mode == INCREMENTAL_COMPACTION) {
4784 __ CallCFunction(
4785 ExternalReference::incremental_evacuation_record_write_function(
4786 masm->isolate()),
4787 argument_count);
4788 } else {
4789 ASSERT(mode == INCREMENTAL);
4790 __ CallCFunction(
4791 ExternalReference::incremental_marking_record_write_function(
4792 masm->isolate()),
4793 argument_count);
4794 }
4795 regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode_);
4796}
4797
4798
4799void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
4800 MacroAssembler* masm,
4801 OnNoNeedToInformIncrementalMarker on_no_need,
4802 Mode mode) {
4803 Label object_is_black, need_incremental, need_incremental_pop_object;
4804
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004805 __ mov(regs_.scratch0(), Immediate(~Page::kPageAlignmentMask));
4806 __ and_(regs_.scratch0(), regs_.object());
4807 __ mov(regs_.scratch1(),
4808 Operand(regs_.scratch0(),
4809 MemoryChunk::kWriteBarrierCounterOffset));
4810 __ sub(regs_.scratch1(), Immediate(1));
4811 __ mov(Operand(regs_.scratch0(),
4812 MemoryChunk::kWriteBarrierCounterOffset),
4813 regs_.scratch1());
4814 __ j(negative, &need_incremental);
4815
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004816 // Let's look at the color of the object: If it is not black we don't have
4817 // to inform the incremental marker.
4818 __ JumpIfBlack(regs_.object(),
4819 regs_.scratch0(),
4820 regs_.scratch1(),
4821 &object_is_black,
4822 Label::kNear);
4823
4824 regs_.Restore(masm);
4825 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
4826 __ RememberedSetHelper(object_,
4827 address_,
4828 value_,
4829 save_fp_regs_mode_,
4830 MacroAssembler::kReturnAtEnd);
4831 } else {
4832 __ ret(0);
4833 }
4834
4835 __ bind(&object_is_black);
4836
4837 // Get the value from the slot.
4838 __ mov(regs_.scratch0(), Operand(regs_.address(), 0));
4839
4840 if (mode == INCREMENTAL_COMPACTION) {
4841 Label ensure_not_white;
4842
4843 __ CheckPageFlag(regs_.scratch0(), // Contains value.
4844 regs_.scratch1(), // Scratch.
4845 MemoryChunk::kEvacuationCandidateMask,
4846 zero,
4847 &ensure_not_white,
4848 Label::kNear);
4849
4850 __ CheckPageFlag(regs_.object(),
4851 regs_.scratch1(), // Scratch.
4852 MemoryChunk::kSkipEvacuationSlotsRecordingMask,
4853 not_zero,
4854 &ensure_not_white,
4855 Label::kNear);
4856
4857 __ jmp(&need_incremental);
4858
4859 __ bind(&ensure_not_white);
4860 }
4861
4862 // We need an extra register for this, so we push the object register
4863 // temporarily.
4864 __ push(regs_.object());
4865 __ EnsureNotWhite(regs_.scratch0(), // The value.
4866 regs_.scratch1(), // Scratch.
4867 regs_.object(), // Scratch.
4868 &need_incremental_pop_object,
4869 Label::kNear);
4870 __ pop(regs_.object());
4871
4872 regs_.Restore(masm);
4873 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
4874 __ RememberedSetHelper(object_,
4875 address_,
4876 value_,
4877 save_fp_regs_mode_,
4878 MacroAssembler::kReturnAtEnd);
4879 } else {
4880 __ ret(0);
4881 }
4882
4883 __ bind(&need_incremental_pop_object);
4884 __ pop(regs_.object());
4885
4886 __ bind(&need_incremental);
4887
4888 // Fall through when we need to inform the incremental marker.
4889}
4890
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004891
4892void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
4893 // ----------- S t a t e -------------
4894 // -- eax : element value to store
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004895 // -- ecx : element index as smi
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004896 // -- esp[0] : return address
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00004897 // -- esp[4] : array literal index in function
4898 // -- esp[8] : array literal
4899 // clobbers ebx, edx, edi
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004900 // -----------------------------------
4901
4902 Label element_done;
4903 Label double_elements;
4904 Label smi_element;
4905 Label slow_elements;
4906 Label slow_elements_from_double;
4907 Label fast_elements;
4908
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00004909 // Get array literal index, array literal and its map.
4910 __ mov(edx, Operand(esp, 1 * kPointerSize));
4911 __ mov(ebx, Operand(esp, 2 * kPointerSize));
4912 __ mov(edi, FieldOperand(ebx, JSObject::kMapOffset));
4913
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004914 __ CheckFastElements(edi, &double_elements);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004915
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004916 // Check for FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS elements
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004917 __ JumpIfSmi(eax, &smi_element);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004918 __ CheckFastSmiElements(edi, &fast_elements, Label::kNear);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004919
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004920 // Store into the array literal requires a elements transition. Call into
4921 // the runtime.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004922
4923 __ bind(&slow_elements);
4924 __ pop(edi); // Pop return address and remember to put back later for tail
4925 // call.
4926 __ push(ebx);
4927 __ push(ecx);
4928 __ push(eax);
4929 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4930 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
4931 __ push(edx);
4932 __ push(edi); // Return return address so that tail call returns to right
4933 // place.
4934 __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
4935
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004936 __ bind(&slow_elements_from_double);
4937 __ pop(edx);
4938 __ jmp(&slow_elements);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004939
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004940 // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004941 __ bind(&fast_elements);
4942 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
4943 __ lea(ecx, FieldOperand(ebx, ecx, times_half_pointer_size,
4944 FixedArrayBase::kHeaderSize));
4945 __ mov(Operand(ecx, 0), eax);
4946 // Update the write barrier for the array store.
4947 __ RecordWrite(ebx, ecx, eax,
4948 kDontSaveFPRegs,
4949 EMIT_REMEMBERED_SET,
4950 OMIT_SMI_CHECK);
4951 __ ret(0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004952
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004953 // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS,
4954 // and value is Smi.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004955 __ bind(&smi_element);
4956 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
4957 __ mov(FieldOperand(ebx, ecx, times_half_pointer_size,
4958 FixedArrayBase::kHeaderSize), eax);
4959 __ ret(0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004960
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004961 // Array literal has ElementsKind of FAST_*_DOUBLE_ELEMENTS.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004962 __ bind(&double_elements);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004963
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004964 __ push(edx);
4965 __ mov(edx, FieldOperand(ebx, JSObject::kElementsOffset));
4966 __ StoreNumberToDoubleElements(eax,
4967 edx,
4968 ecx,
4969 edi,
4970 xmm0,
4971 &slow_elements_from_double,
4972 false);
4973 __ pop(edx);
4974 __ ret(0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004975}
4976
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004977
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00004978void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004979 CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004980 __ call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00004981 int parameter_count_offset =
4982 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
4983 __ mov(ebx, MemOperand(ebp, parameter_count_offset));
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00004984 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00004985 __ pop(ecx);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00004986 int additional_offset = function_mode_ == JS_FUNCTION_STUB_MODE
4987 ? kPointerSize
4988 : 0;
4989 __ lea(esp, MemOperand(esp, ebx, times_pointer_size, additional_offset));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00004990 __ jmp(ecx); // Return to IC Miss stub, continuation still on stack.
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00004991}
4992
4993
machenbach@chromium.orgea468882013-11-18 08:53:19 +00004994void StubFailureTailCallTrampolineStub::Generate(MacroAssembler* masm) {
4995 CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
4996 __ call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
4997 __ mov(edi, eax);
4998 int parameter_count_offset =
4999 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
5000 __ mov(eax, MemOperand(ebp, parameter_count_offset));
5001 // The parameter count above includes the receiver for the arguments passed to
5002 // the deoptimization handler. Subtract the receiver for the parameter count
5003 // for the call.
5004 __ sub(eax, Immediate(1));
5005 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
5006 ParameterCount argument_count(eax);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00005007 __ InvokeFunction(edi, argument_count, JUMP_FUNCTION, NullCallWrapper());
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005008}
5009
5010
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005011void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005012 if (masm->isolate()->function_entry_hook() != NULL) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005013 ProfileEntryHookStub stub;
5014 masm->CallStub(&stub);
5015 }
5016}
5017
5018
5019void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005020 // Save volatile registers.
5021 const int kNumSavedRegisters = 3;
5022 __ push(eax);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005023 __ push(ecx);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005024 __ push(edx);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005025
5026 // Calculate and push the original stack pointer.
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00005027 __ lea(eax, Operand(esp, (kNumSavedRegisters + 1) * kPointerSize));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005028 __ push(eax);
5029
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00005030 // Retrieve our return address and use it to calculate the calling
5031 // function's address.
5032 __ mov(eax, Operand(esp, (kNumSavedRegisters + 1) * kPointerSize));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005033 __ sub(eax, Immediate(Assembler::kCallInstructionLength));
5034 __ push(eax);
5035
5036 // Call the entry hook.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005037 ASSERT(masm->isolate()->function_entry_hook() != NULL);
5038 __ call(FUNCTION_ADDR(masm->isolate()->function_entry_hook()),
5039 RelocInfo::RUNTIME_ENTRY);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005040 __ add(esp, Immediate(2 * kPointerSize));
5041
5042 // Restore ecx.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005043 __ pop(edx);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005044 __ pop(ecx);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005045 __ pop(eax);
5046
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005047 __ ret(0);
5048}
5049
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005050
5051template<class T>
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005052static void CreateArrayDispatch(MacroAssembler* masm,
5053 AllocationSiteOverrideMode mode) {
5054 if (mode == DISABLE_ALLOCATION_SITES) {
5055 T stub(GetInitialFastElementsKind(),
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005056 mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005057 __ TailCallStub(&stub);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005058 } else if (mode == DONT_OVERRIDE) {
5059 int last_index = GetSequenceIndexFromFastElementsKind(
5060 TERMINAL_FAST_ELEMENTS_KIND);
5061 for (int i = 0; i <= last_index; ++i) {
5062 Label next;
5063 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
5064 __ cmp(edx, kind);
5065 __ j(not_equal, &next);
5066 T stub(kind);
5067 __ TailCallStub(&stub);
5068 __ bind(&next);
5069 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005070
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005071 // If we reached this point there is a problem.
5072 __ Abort(kUnexpectedElementsKindInArrayConstructor);
5073 } else {
5074 UNREACHABLE();
5075 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005076}
5077
5078
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005079static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
5080 AllocationSiteOverrideMode mode) {
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00005081 // ebx - allocation site (if mode != DISABLE_ALLOCATION_SITES)
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005082 // edx - kind (if mode != DISABLE_ALLOCATION_SITES)
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005083 // eax - number of arguments
5084 // edi - constructor?
5085 // esp[0] - return address
5086 // esp[4] - last argument
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005087 Label normal_sequence;
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005088 if (mode == DONT_OVERRIDE) {
5089 ASSERT(FAST_SMI_ELEMENTS == 0);
5090 ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
5091 ASSERT(FAST_ELEMENTS == 2);
5092 ASSERT(FAST_HOLEY_ELEMENTS == 3);
5093 ASSERT(FAST_DOUBLE_ELEMENTS == 4);
5094 ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
5095
5096 // is the low bit set? If so, we are holey and that is good.
5097 __ test_b(edx, 1);
5098 __ j(not_zero, &normal_sequence);
5099 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005100
5101 // look at the first argument
5102 __ mov(ecx, Operand(esp, kPointerSize));
5103 __ test(ecx, ecx);
5104 __ j(zero, &normal_sequence);
5105
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005106 if (mode == DISABLE_ALLOCATION_SITES) {
5107 ElementsKind initial = GetInitialFastElementsKind();
5108 ElementsKind holey_initial = GetHoleyElementsKind(initial);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005109
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005110 ArraySingleArgumentConstructorStub stub_holey(holey_initial,
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005111 DISABLE_ALLOCATION_SITES);
5112 __ TailCallStub(&stub_holey);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005113
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005114 __ bind(&normal_sequence);
5115 ArraySingleArgumentConstructorStub stub(initial,
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005116 DISABLE_ALLOCATION_SITES);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005117 __ TailCallStub(&stub);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005118 } else if (mode == DONT_OVERRIDE) {
5119 // We are going to create a holey array, but our kind is non-holey.
5120 // Fix kind and retry.
5121 __ inc(edx);
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00005122
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005123 if (FLAG_debug_code) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005124 Handle<Map> allocation_site_map =
5125 masm->isolate()->factory()->allocation_site_map();
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00005126 __ cmp(FieldOperand(ebx, 0), Immediate(allocation_site_map));
5127 __ Assert(equal, kExpectedAllocationSite);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005128 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005129
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00005130 // Save the resulting elements kind in type info. We can't just store r3
5131 // in the AllocationSite::transition_info field because elements kind is
5132 // restricted to a portion of the field...upper bits need to be left alone.
5133 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00005134 __ add(FieldOperand(ebx, AllocationSite::kTransitionInfoOffset),
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00005135 Immediate(Smi::FromInt(kFastElementsKindPackedToHoley)));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005136
5137 __ bind(&normal_sequence);
5138 int last_index = GetSequenceIndexFromFastElementsKind(
5139 TERMINAL_FAST_ELEMENTS_KIND);
5140 for (int i = 0; i <= last_index; ++i) {
5141 Label next;
5142 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
5143 __ cmp(edx, kind);
5144 __ j(not_equal, &next);
5145 ArraySingleArgumentConstructorStub stub(kind);
5146 __ TailCallStub(&stub);
5147 __ bind(&next);
5148 }
5149
5150 // If we reached this point there is a problem.
5151 __ Abort(kUnexpectedElementsKindInArrayConstructor);
5152 } else {
5153 UNREACHABLE();
5154 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005155}
5156
5157
5158template<class T>
5159static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
5160 int to_index = GetSequenceIndexFromFastElementsKind(
5161 TERMINAL_FAST_ELEMENTS_KIND);
5162 for (int i = 0; i <= to_index; ++i) {
5163 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005164 T stub(kind);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00005165 stub.GetCode(isolate);
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00005166 if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
machenbach@chromium.org03453962014-01-10 14:16:31 +00005167 T stub1(kind, DISABLE_ALLOCATION_SITES);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00005168 stub1.GetCode(isolate);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005169 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005170 }
5171}
5172
5173
5174void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) {
5175 ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>(
5176 isolate);
5177 ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>(
5178 isolate);
5179 ArrayConstructorStubAheadOfTimeHelper<ArrayNArgumentsConstructorStub>(
5180 isolate);
5181}
5182
5183
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005184void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(
5185 Isolate* isolate) {
5186 ElementsKind kinds[2] = { FAST_ELEMENTS, FAST_HOLEY_ELEMENTS };
5187 for (int i = 0; i < 2; i++) {
5188 // For internal arrays we only need a few things
5189 InternalArrayNoArgumentConstructorStub stubh1(kinds[i]);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00005190 stubh1.GetCode(isolate);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005191 InternalArraySingleArgumentConstructorStub stubh2(kinds[i]);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00005192 stubh2.GetCode(isolate);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005193 InternalArrayNArgumentsConstructorStub stubh3(kinds[i]);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00005194 stubh3.GetCode(isolate);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005195 }
5196}
5197
5198
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005199void ArrayConstructorStub::GenerateDispatchToArrayStub(
5200 MacroAssembler* masm,
5201 AllocationSiteOverrideMode mode) {
5202 if (argument_count_ == ANY) {
5203 Label not_zero_case, not_one_case;
5204 __ test(eax, eax);
5205 __ j(not_zero, &not_zero_case);
5206 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
5207
5208 __ bind(&not_zero_case);
5209 __ cmp(eax, 1);
5210 __ j(greater, &not_one_case);
5211 CreateArrayDispatchOneArgument(masm, mode);
5212
5213 __ bind(&not_one_case);
5214 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
5215 } else if (argument_count_ == NONE) {
5216 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
5217 } else if (argument_count_ == ONE) {
5218 CreateArrayDispatchOneArgument(masm, mode);
5219 } else if (argument_count_ == MORE_THAN_ONE) {
5220 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
5221 } else {
5222 UNREACHABLE();
5223 }
5224}
5225
5226
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005227void ArrayConstructorStub::Generate(MacroAssembler* masm) {
5228 // ----------- S t a t e -------------
5229 // -- eax : argc (only if argument_count_ == ANY)
5230 // -- ebx : type info cell
5231 // -- edi : constructor
5232 // -- esp[0] : return address
5233 // -- esp[4] : last argument
5234 // -----------------------------------
5235 Handle<Object> undefined_sentinel(
5236 masm->isolate()->heap()->undefined_value(),
5237 masm->isolate());
5238
5239 if (FLAG_debug_code) {
5240 // The array construct code is only set for the global and natives
5241 // builtin Array functions which always have maps.
5242
5243 // Initial map for the builtin Array function should be a map.
5244 __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
5245 // Will both indicate a NULL and a Smi.
5246 __ test(ecx, Immediate(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +00005247 __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005248 __ CmpObjectType(ecx, MAP_TYPE, ecx);
danno@chromium.org59400602013-08-13 17:09:37 +00005249 __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005250
danno@chromium.org41728482013-06-12 22:31:22 +00005251 // We should either have undefined in ebx or a valid cell
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005252 Label okay_here;
danno@chromium.org41728482013-06-12 22:31:22 +00005253 Handle<Map> cell_map = masm->isolate()->factory()->cell_map();
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005254 __ cmp(ebx, Immediate(undefined_sentinel));
5255 __ j(equal, &okay_here);
danno@chromium.org41728482013-06-12 22:31:22 +00005256 __ cmp(FieldOperand(ebx, 0), Immediate(cell_map));
danno@chromium.org59400602013-08-13 17:09:37 +00005257 __ Assert(equal, kExpectedPropertyCellInRegisterEbx);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005258 __ bind(&okay_here);
5259 }
5260
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005261 Label no_info;
5262 // If the type cell is undefined, or contains anything other than an
5263 // AllocationSite, call an array constructor that doesn't use AllocationSites.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005264 __ cmp(ebx, Immediate(undefined_sentinel));
5265 __ j(equal, &no_info);
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00005266 __ mov(ebx, FieldOperand(ebx, Cell::kValueOffset));
5267 __ cmp(FieldOperand(ebx, 0), Immediate(
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005268 masm->isolate()->factory()->allocation_site_map()));
danno@chromium.orgbee51992013-07-10 14:57:15 +00005269 __ j(not_equal, &no_info);
5270
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00005271 // Only look at the lower 16 bits of the transition info.
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00005272 __ mov(edx, FieldOperand(ebx, AllocationSite::kTransitionInfoOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005273 __ SmiUntag(edx);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00005274 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
5275 __ and_(edx, Immediate(AllocationSite::ElementsKindBits::kMask));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005276 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
5277
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005278 __ bind(&no_info);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005279 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005280}
5281
5282
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005283void InternalArrayConstructorStub::GenerateCase(
5284 MacroAssembler* masm, ElementsKind kind) {
5285 Label not_zero_case, not_one_case;
5286 Label normal_sequence;
5287
5288 __ test(eax, eax);
5289 __ j(not_zero, &not_zero_case);
5290 InternalArrayNoArgumentConstructorStub stub0(kind);
5291 __ TailCallStub(&stub0);
5292
5293 __ bind(&not_zero_case);
5294 __ cmp(eax, 1);
5295 __ j(greater, &not_one_case);
5296
5297 if (IsFastPackedElementsKind(kind)) {
5298 // We might need to create a holey array
5299 // look at the first argument
5300 __ mov(ecx, Operand(esp, kPointerSize));
5301 __ test(ecx, ecx);
5302 __ j(zero, &normal_sequence);
5303
5304 InternalArraySingleArgumentConstructorStub
5305 stub1_holey(GetHoleyElementsKind(kind));
5306 __ TailCallStub(&stub1_holey);
5307 }
5308
5309 __ bind(&normal_sequence);
5310 InternalArraySingleArgumentConstructorStub stub1(kind);
5311 __ TailCallStub(&stub1);
5312
5313 __ bind(&not_one_case);
5314 InternalArrayNArgumentsConstructorStub stubN(kind);
5315 __ TailCallStub(&stubN);
5316}
5317
5318
5319void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
5320 // ----------- S t a t e -------------
5321 // -- eax : argc
5322 // -- ebx : type info cell
5323 // -- edi : constructor
5324 // -- esp[0] : return address
5325 // -- esp[4] : last argument
5326 // -----------------------------------
5327
5328 if (FLAG_debug_code) {
5329 // The array construct code is only set for the global and natives
5330 // builtin Array functions which always have maps.
5331
5332 // Initial map for the builtin Array function should be a map.
5333 __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
5334 // Will both indicate a NULL and a Smi.
5335 __ test(ecx, Immediate(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +00005336 __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005337 __ CmpObjectType(ecx, MAP_TYPE, ecx);
danno@chromium.org59400602013-08-13 17:09:37 +00005338 __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005339 }
5340
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005341 // Figure out the right elements kind
5342 __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005343
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005344 // Load the map's "bit field 2" into |result|. We only need the first byte,
5345 // but the following masking takes care of that anyway.
5346 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
5347 // Retrieve elements_kind from bit field 2.
5348 __ and_(ecx, Map::kElementsKindMask);
5349 __ shr(ecx, Map::kElementsKindShift);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005350
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005351 if (FLAG_debug_code) {
5352 Label done;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005353 __ cmp(ecx, Immediate(FAST_ELEMENTS));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005354 __ j(equal, &done);
5355 __ cmp(ecx, Immediate(FAST_HOLEY_ELEMENTS));
5356 __ Assert(equal,
danno@chromium.org59400602013-08-13 17:09:37 +00005357 kInvalidElementsKindForInternalArrayOrInternalPackedArray);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005358 __ bind(&done);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005359 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005360
5361 Label fast_elements_case;
5362 __ cmp(ecx, Immediate(FAST_ELEMENTS));
5363 __ j(equal, &fast_elements_case);
5364 GenerateCase(masm, FAST_HOLEY_ELEMENTS);
5365
5366 __ bind(&fast_elements_case);
5367 GenerateCase(masm, FAST_ELEMENTS);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005368}
5369
5370
ricow@chromium.org65fae842010-08-25 15:26:24 +00005371#undef __
5372
5373} } // namespace v8::internal
5374
5375#endif // V8_TARGET_ARCH_IA32