blob: 0bd39308abc1abbd3e80f81e0db3ca8fa8f62a31 [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
machenbach@chromium.org09cae8d2014-01-30 01:05:27 +0000142void RegExpConstructResultStub::InitializeInterfaceDescriptor(
143 Isolate* isolate,
144 CodeStubInterfaceDescriptor* descriptor) {
145 static Register registers[] = { ecx, ebx, eax };
146 descriptor->register_param_count_ = 3;
147 descriptor->register_params_ = registers;
148 descriptor->deoptimization_handler_ =
149 Runtime::FunctionForId(Runtime::kRegExpConstructResult)->entry;
150}
151
152
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000153void LoadFieldStub::InitializeInterfaceDescriptor(
154 Isolate* isolate,
155 CodeStubInterfaceDescriptor* descriptor) {
156 static Register registers[] = { edx };
157 descriptor->register_param_count_ = 1;
158 descriptor->register_params_ = registers;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000159 descriptor->deoptimization_handler_ = NULL;
160}
161
162
163void KeyedLoadFieldStub::InitializeInterfaceDescriptor(
164 Isolate* isolate,
165 CodeStubInterfaceDescriptor* descriptor) {
166 static Register registers[] = { edx };
167 descriptor->register_param_count_ = 1;
168 descriptor->register_params_ = registers;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000169 descriptor->deoptimization_handler_ = NULL;
170}
171
172
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000173void KeyedArrayCallStub::InitializeInterfaceDescriptor(
174 Isolate* isolate,
175 CodeStubInterfaceDescriptor* descriptor) {
176 static Register registers[] = { ecx };
177 descriptor->register_param_count_ = 1;
178 descriptor->register_params_ = registers;
179 descriptor->continuation_type_ = TAIL_CALL_CONTINUATION;
180 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
181 descriptor->deoptimization_handler_ =
182 FUNCTION_ADDR(KeyedCallIC_MissFromStubFailure);
183}
184
185
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000186void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
187 Isolate* isolate,
188 CodeStubInterfaceDescriptor* descriptor) {
189 static Register registers[] = { edx, ecx, eax };
190 descriptor->register_param_count_ = 3;
191 descriptor->register_params_ = registers;
192 descriptor->deoptimization_handler_ =
193 FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure);
194}
195
196
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000197void TransitionElementsKindStub::InitializeInterfaceDescriptor(
198 Isolate* isolate,
199 CodeStubInterfaceDescriptor* descriptor) {
200 static Register registers[] = { eax, ebx };
201 descriptor->register_param_count_ = 2;
202 descriptor->register_params_ = registers;
203 descriptor->deoptimization_handler_ =
204 Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry;
205}
206
207
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000208static void InitializeArrayConstructorDescriptor(
209 Isolate* isolate,
210 CodeStubInterfaceDescriptor* descriptor,
211 int constant_stack_parameter_count) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000212 // register state
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000213 // eax -- number of arguments
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000214 // edi -- function
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +0000215 // ebx -- allocation site with elements kind
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000216 static Register registers_variable_args[] = { edi, ebx, eax };
217 static Register registers_no_args[] = { edi, ebx };
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000218
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000219 if (constant_stack_parameter_count == 0) {
220 descriptor->register_param_count_ = 2;
221 descriptor->register_params_ = registers_no_args;
222 } else {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000223 // stack param count needs (constructor pointer, and single argument)
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000224 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000225 descriptor->stack_parameter_count_ = eax;
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000226 descriptor->register_param_count_ = 3;
227 descriptor->register_params_ = registers_variable_args;
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000228 }
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000229
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000230 descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000231 descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000232 descriptor->deoptimization_handler_ =
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000233 Runtime::FunctionForId(Runtime::kArrayConstructor)->entry;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000234}
235
236
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000237static void InitializeInternalArrayConstructorDescriptor(
238 Isolate* isolate,
239 CodeStubInterfaceDescriptor* descriptor,
240 int constant_stack_parameter_count) {
241 // register state
242 // eax -- number of arguments
243 // edi -- constructor function
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000244 static Register registers_variable_args[] = { edi, eax };
245 static Register registers_no_args[] = { edi };
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000246
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000247 if (constant_stack_parameter_count == 0) {
248 descriptor->register_param_count_ = 1;
249 descriptor->register_params_ = registers_no_args;
250 } else {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000251 // stack param count needs (constructor pointer, and single argument)
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000252 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000253 descriptor->stack_parameter_count_ = eax;
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000254 descriptor->register_param_count_ = 2;
255 descriptor->register_params_ = registers_variable_args;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000256 }
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000257
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000258 descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000259 descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
260 descriptor->deoptimization_handler_ =
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000261 Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000262}
263
264
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000265void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor(
266 Isolate* isolate,
267 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000268 InitializeArrayConstructorDescriptor(isolate, descriptor, 0);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000269}
270
271
272void ArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor(
273 Isolate* isolate,
274 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000275 InitializeArrayConstructorDescriptor(isolate, descriptor, 1);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000276}
277
278
279void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
280 Isolate* isolate,
281 CodeStubInterfaceDescriptor* descriptor) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000282 InitializeArrayConstructorDescriptor(isolate, descriptor, -1);
283}
284
285
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000286void InternalArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor(
287 Isolate* isolate,
288 CodeStubInterfaceDescriptor* descriptor) {
289 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 0);
290}
291
292
293void InternalArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor(
294 Isolate* isolate,
295 CodeStubInterfaceDescriptor* descriptor) {
296 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 1);
297}
298
299
300void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
301 Isolate* isolate,
302 CodeStubInterfaceDescriptor* descriptor) {
303 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, -1);
304}
305
306
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000307void CompareNilICStub::InitializeInterfaceDescriptor(
308 Isolate* isolate,
309 CodeStubInterfaceDescriptor* descriptor) {
310 static Register registers[] = { eax };
311 descriptor->register_param_count_ = 1;
312 descriptor->register_params_ = registers;
313 descriptor->deoptimization_handler_ =
314 FUNCTION_ADDR(CompareNilIC_Miss);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000315 descriptor->SetMissHandler(
316 ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000317}
318
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000319void ToBooleanStub::InitializeInterfaceDescriptor(
320 Isolate* isolate,
321 CodeStubInterfaceDescriptor* descriptor) {
322 static Register registers[] = { eax };
323 descriptor->register_param_count_ = 1;
324 descriptor->register_params_ = registers;
325 descriptor->deoptimization_handler_ =
326 FUNCTION_ADDR(ToBooleanIC_Miss);
327 descriptor->SetMissHandler(
328 ExternalReference(IC_Utility(IC::kToBooleanIC_Miss), isolate));
329}
330
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000331
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000332void StoreGlobalStub::InitializeInterfaceDescriptor(
333 Isolate* isolate,
334 CodeStubInterfaceDescriptor* descriptor) {
335 static Register registers[] = { edx, ecx, eax };
336 descriptor->register_param_count_ = 3;
337 descriptor->register_params_ = registers;
338 descriptor->deoptimization_handler_ =
339 FUNCTION_ADDR(StoreIC_MissFromStubFailure);
340}
341
342
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000343void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor(
344 Isolate* isolate,
345 CodeStubInterfaceDescriptor* descriptor) {
346 static Register registers[] = { eax, ebx, ecx, edx };
347 descriptor->register_param_count_ = 4;
348 descriptor->register_params_ = registers;
349 descriptor->deoptimization_handler_ =
350 FUNCTION_ADDR(ElementsTransitionAndStoreIC_Miss);
351}
352
353
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +0000354void BinaryOpICStub::InitializeInterfaceDescriptor(
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +0000355 Isolate* isolate,
356 CodeStubInterfaceDescriptor* descriptor) {
357 static Register registers[] = { edx, eax };
358 descriptor->register_param_count_ = 2;
359 descriptor->register_params_ = registers;
360 descriptor->deoptimization_handler_ = FUNCTION_ADDR(BinaryOpIC_Miss);
361 descriptor->SetMissHandler(
362 ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate));
363}
364
365
ulan@chromium.org0f13e742014-01-03 15:51:11 +0000366void BinaryOpWithAllocationSiteStub::InitializeInterfaceDescriptor(
367 Isolate* isolate,
368 CodeStubInterfaceDescriptor* descriptor) {
369 static Register registers[] = { ecx, edx, eax };
370 descriptor->register_param_count_ = 3;
371 descriptor->register_params_ = registers;
372 descriptor->deoptimization_handler_ =
373 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite);
374}
375
376
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +0000377void StringAddStub::InitializeInterfaceDescriptor(
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000378 Isolate* isolate,
379 CodeStubInterfaceDescriptor* descriptor) {
380 static Register registers[] = { edx, eax };
381 descriptor->register_param_count_ = 2;
382 descriptor->register_params_ = registers;
383 descriptor->deoptimization_handler_ =
384 Runtime::FunctionForId(Runtime::kStringAdd)->entry;
385}
386
387
machenbach@chromium.org26ca35c2014-01-16 08:22:55 +0000388void CallDescriptors::InitializeForIsolate(Isolate* isolate) {
389 {
390 CallInterfaceDescriptor* descriptor =
391 isolate->call_descriptor(Isolate::ArgumentAdaptorCall);
392 static Register registers[] = { edi, // JSFunction
393 esi, // context
394 eax, // actual number of arguments
395 ebx, // expected number of arguments
396 };
397 static Representation representations[] = {
398 Representation::Tagged(), // JSFunction
399 Representation::Tagged(), // context
400 Representation::Integer32(), // actual number of arguments
401 Representation::Integer32(), // expected number of arguments
402 };
403 descriptor->register_param_count_ = 4;
404 descriptor->register_params_ = registers;
405 descriptor->param_representations_ = representations;
406 }
407 {
408 CallInterfaceDescriptor* descriptor =
409 isolate->call_descriptor(Isolate::KeyedCall);
410 static Register registers[] = { esi, // context
411 ecx, // key
412 };
413 static Representation representations[] = {
414 Representation::Tagged(), // context
415 Representation::Tagged(), // key
416 };
417 descriptor->register_param_count_ = 2;
418 descriptor->register_params_ = registers;
419 descriptor->param_representations_ = representations;
420 }
421 {
422 CallInterfaceDescriptor* descriptor =
423 isolate->call_descriptor(Isolate::NamedCall);
424 static Register registers[] = { esi, // context
425 ecx, // name
426 };
427 static Representation representations[] = {
428 Representation::Tagged(), // context
429 Representation::Tagged(), // name
430 };
431 descriptor->register_param_count_ = 2;
432 descriptor->register_params_ = registers;
433 descriptor->param_representations_ = representations;
434 }
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +0000435 {
436 CallInterfaceDescriptor* descriptor =
437 isolate->call_descriptor(Isolate::CallHandler);
438 static Register registers[] = { esi, // context
439 edx, // receiver
440 };
441 static Representation representations[] = {
442 Representation::Tagged(), // context
443 Representation::Tagged(), // receiver
444 };
445 descriptor->register_param_count_ = 2;
446 descriptor->register_params_ = registers;
447 descriptor->param_representations_ = representations;
448 }
machenbach@chromium.org26ca35c2014-01-16 08:22:55 +0000449}
450
451
ricow@chromium.org65fae842010-08-25 15:26:24 +0000452#define __ ACCESS_MASM(masm)
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000453
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000454
455void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) {
456 // Update the static counter each time a new code stub is generated.
457 Isolate* isolate = masm->isolate();
458 isolate->counters()->code_stubs()->Increment();
459
460 CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate);
461 int param_count = descriptor->register_param_count_;
462 {
463 // Call the runtime system in a fresh internal frame.
464 FrameScope scope(masm, StackFrame::INTERNAL);
465 ASSERT(descriptor->register_param_count_ == 0 ||
466 eax.is(descriptor->register_params_[param_count - 1]));
467 // Push arguments
468 for (int i = 0; i < param_count; ++i) {
469 __ push(descriptor->register_params_[i]);
470 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000471 ExternalReference miss = descriptor->miss_handler();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000472 __ CallExternalReference(miss, descriptor->register_param_count_);
473 }
474
475 __ ret(0);
476}
477
478
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000479void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
480 // We don't allow a GC during a store buffer overflow so there is no need to
481 // store the registers in any particular way, but we do have to store and
482 // restore them.
483 __ pushad();
484 if (save_doubles_ == kSaveFPRegs) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000485 CpuFeatureScope scope(masm, SSE2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000486 __ sub(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters));
487 for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
488 XMMRegister reg = XMMRegister::from_code(i);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000489 __ movsd(Operand(esp, i * kDoubleSize), reg);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000490 }
491 }
492 const int argument_count = 1;
493
494 AllowExternalCallThatCantCauseGC scope(masm);
495 __ PrepareCallCFunction(argument_count, ecx);
496 __ mov(Operand(esp, 0 * kPointerSize),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000497 Immediate(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000498 __ CallCFunction(
499 ExternalReference::store_buffer_overflow_function(masm->isolate()),
500 argument_count);
501 if (save_doubles_ == kSaveFPRegs) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000502 CpuFeatureScope scope(masm, SSE2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000503 for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
504 XMMRegister reg = XMMRegister::from_code(i);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000505 __ movsd(reg, Operand(esp, i * kDoubleSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000506 }
507 __ add(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters));
508 }
509 __ popad();
510 __ ret(0);
511}
512
513
ricow@chromium.org65fae842010-08-25 15:26:24 +0000514class FloatingPointHelper : public AllStatic {
515 public:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000516 enum ArgLocation {
517 ARGS_ON_STACK,
518 ARGS_IN_REGISTERS
519 };
520
521 // Code pattern for loading a floating point value. Input value must
522 // be either a smi or a heap number object (fp value). Requirements:
523 // operand in register number. Returns operand as floating point number
524 // on FPU stack.
525 static void LoadFloatOperand(MacroAssembler* masm, Register number);
526
ricow@chromium.org65fae842010-08-25 15:26:24 +0000527 // Test if operands are smi or number objects (fp). Requirements:
528 // operand_1 in eax, operand_2 in edx; falls through on float
529 // operands, jumps to the non_float label otherwise.
530 static void CheckFloatOperands(MacroAssembler* masm,
531 Label* non_float,
532 Register scratch);
533
ricow@chromium.org65fae842010-08-25 15:26:24 +0000534 // Test if operands are numbers (smi or HeapNumber objects), and load
535 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if
536 // either operand is not a number. Operands are in edx and eax.
537 // Leaves operands unchanged.
538 static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000539};
540
541
danno@chromium.org169691d2013-07-15 08:01:13 +0000542void DoubleToIStub::Generate(MacroAssembler* masm) {
543 Register input_reg = this->source();
544 Register final_result_reg = this->destination();
545 ASSERT(is_truncating());
546
547 Label check_negative, process_64_bits, done, done_no_stash;
548
549 int double_offset = offset();
550
551 // Account for return address and saved regs if input is esp.
552 if (input_reg.is(esp)) double_offset += 3 * kPointerSize;
553
554 MemOperand mantissa_operand(MemOperand(input_reg, double_offset));
555 MemOperand exponent_operand(MemOperand(input_reg,
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000556 double_offset + kDoubleSize / 2));
danno@chromium.org169691d2013-07-15 08:01:13 +0000557
558 Register scratch1;
559 {
560 Register scratch_candidates[3] = { ebx, edx, edi };
561 for (int i = 0; i < 3; i++) {
562 scratch1 = scratch_candidates[i];
563 if (!final_result_reg.is(scratch1) && !input_reg.is(scratch1)) break;
564 }
565 }
566 // Since we must use ecx for shifts below, use some other register (eax)
567 // to calculate the result if ecx is the requested return register.
568 Register result_reg = final_result_reg.is(ecx) ? eax : final_result_reg;
569 // Save ecx if it isn't the return register and therefore volatile, or if it
570 // is the return register, then save the temp register we use in its stead for
571 // the result.
572 Register save_reg = final_result_reg.is(ecx) ? eax : ecx;
573 __ push(scratch1);
574 __ push(save_reg);
575
576 bool stash_exponent_copy = !input_reg.is(esp);
577 __ mov(scratch1, mantissa_operand);
578 if (CpuFeatures::IsSupported(SSE3)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000579 CpuFeatureScope scope(masm, SSE3);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000580 // Load x87 register with heap number.
danno@chromium.org169691d2013-07-15 08:01:13 +0000581 __ fld_d(mantissa_operand);
582 }
583 __ mov(ecx, exponent_operand);
584 if (stash_exponent_copy) __ push(ecx);
585
586 __ and_(ecx, HeapNumber::kExponentMask);
587 __ shr(ecx, HeapNumber::kExponentShift);
588 __ lea(result_reg, MemOperand(ecx, -HeapNumber::kExponentBias));
589 __ cmp(result_reg, Immediate(HeapNumber::kMantissaBits));
590 __ j(below, &process_64_bits);
591
592 // Result is entirely in lower 32-bits of mantissa
593 int delta = HeapNumber::kExponentBias + Double::kPhysicalSignificandSize;
594 if (CpuFeatures::IsSupported(SSE3)) {
595 __ fstp(0);
596 }
597 __ sub(ecx, Immediate(delta));
598 __ xor_(result_reg, result_reg);
599 __ cmp(ecx, Immediate(31));
600 __ j(above, &done);
601 __ shl_cl(scratch1);
602 __ jmp(&check_negative);
603
604 __ bind(&process_64_bits);
605 if (CpuFeatures::IsSupported(SSE3)) {
606 CpuFeatureScope scope(masm, SSE3);
607 if (stash_exponent_copy) {
608 // Already a copy of the exponent on the stack, overwrite it.
609 STATIC_ASSERT(kDoubleSize == 2 * kPointerSize);
610 __ sub(esp, Immediate(kDoubleSize / 2));
611 } else {
612 // Reserve space for 64 bit answer.
613 __ sub(esp, Immediate(kDoubleSize)); // Nolint.
614 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000615 // Do conversion, which cannot fail because we checked the exponent.
616 __ fisttp_d(Operand(esp, 0));
danno@chromium.org169691d2013-07-15 08:01:13 +0000617 __ mov(result_reg, Operand(esp, 0)); // Load low word of answer as result
618 __ add(esp, Immediate(kDoubleSize));
619 __ jmp(&done_no_stash);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000620 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +0000621 // Result must be extracted from shifted 32-bit mantissa
622 __ sub(ecx, Immediate(delta));
623 __ neg(ecx);
624 if (stash_exponent_copy) {
625 __ mov(result_reg, MemOperand(esp, 0));
626 } else {
627 __ mov(result_reg, exponent_operand);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000628 }
danno@chromium.org169691d2013-07-15 08:01:13 +0000629 __ and_(result_reg,
630 Immediate(static_cast<uint32_t>(Double::kSignificandMask >> 32)));
631 __ add(result_reg,
632 Immediate(static_cast<uint32_t>(Double::kHiddenBit >> 32)));
633 __ shrd(result_reg, scratch1);
634 __ shr_cl(result_reg);
635 __ test(ecx, Immediate(32));
636 if (CpuFeatures::IsSupported(CMOV)) {
637 CpuFeatureScope use_cmov(masm, CMOV);
638 __ cmov(not_equal, scratch1, result_reg);
639 } else {
640 Label skip_mov;
641 __ j(equal, &skip_mov, Label::kNear);
642 __ mov(scratch1, result_reg);
643 __ bind(&skip_mov);
644 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000645 }
danno@chromium.org169691d2013-07-15 08:01:13 +0000646
647 // If the double was negative, negate the integer result.
648 __ bind(&check_negative);
649 __ mov(result_reg, scratch1);
650 __ neg(result_reg);
651 if (stash_exponent_copy) {
652 __ cmp(MemOperand(esp, 0), Immediate(0));
653 } else {
654 __ cmp(exponent_operand, Immediate(0));
655 }
656 if (CpuFeatures::IsSupported(CMOV)) {
657 CpuFeatureScope use_cmov(masm, CMOV);
658 __ cmov(greater, result_reg, scratch1);
659 } else {
660 Label skip_mov;
661 __ j(less_equal, &skip_mov, Label::kNear);
662 __ mov(result_reg, scratch1);
663 __ bind(&skip_mov);
664 }
665
666 // Restore registers
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000667 __ bind(&done);
danno@chromium.org169691d2013-07-15 08:01:13 +0000668 if (stash_exponent_copy) {
669 __ add(esp, Immediate(kDoubleSize / 2));
670 }
671 __ bind(&done_no_stash);
672 if (!final_result_reg.is(result_reg)) {
673 ASSERT(final_result_reg.is(ecx));
674 __ mov(final_result_reg, result_reg);
675 }
676 __ pop(save_reg);
677 __ pop(scratch1);
678 __ ret(0);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000679}
680
681
ricow@chromium.org65fae842010-08-25 15:26:24 +0000682void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
683 Register number) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000684 Label load_smi, done;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000685
whesse@chromium.org7b260152011-06-20 15:33:18 +0000686 __ JumpIfSmi(number, &load_smi, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000687 __ fld_d(FieldOperand(number, HeapNumber::kValueOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000688 __ jmp(&done, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000689
690 __ bind(&load_smi);
691 __ SmiUntag(number);
692 __ push(number);
693 __ fild_s(Operand(esp, 0));
694 __ pop(number);
695
696 __ bind(&done);
697}
698
699
ricow@chromium.org65fae842010-08-25 15:26:24 +0000700void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm,
701 Label* not_numbers) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000702 Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000703 // Load operand in edx into xmm0, or branch to not_numbers.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000704 __ JumpIfSmi(edx, &load_smi_edx, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000705 Factory* factory = masm->isolate()->factory();
706 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000707 __ j(not_equal, not_numbers); // Argument in edx is not a number.
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000708 __ movsd(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000709 __ bind(&load_eax);
710 // Load operand in eax into xmm1, or branch to not_numbers.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000711 __ JumpIfSmi(eax, &load_smi_eax, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000712 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map());
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000713 __ j(equal, &load_float_eax, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000714 __ jmp(not_numbers); // Argument in eax is not a number.
715 __ bind(&load_smi_edx);
716 __ SmiUntag(edx); // Untag smi before converting to float.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000717 __ Cvtsi2sd(xmm0, edx);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000718 __ SmiTag(edx); // Retag smi for heap number overwriting test.
719 __ jmp(&load_eax);
720 __ bind(&load_smi_eax);
721 __ SmiUntag(eax); // Untag smi before converting to float.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000722 __ Cvtsi2sd(xmm1, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000723 __ SmiTag(eax); // Retag smi for heap number overwriting test.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000724 __ jmp(&done, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000725 __ bind(&load_float_eax);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000726 __ movsd(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +0000727 __ bind(&done);
728}
729
730
ricow@chromium.org65fae842010-08-25 15:26:24 +0000731void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm,
732 Label* non_float,
733 Register scratch) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000734 Label test_other, done;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000735 // Test if both operands are floats or smi -> scratch=k_is_float;
736 // Otherwise scratch = k_not_float.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000737 __ JumpIfSmi(edx, &test_other, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000738 __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000739 Factory* factory = masm->isolate()->factory();
740 __ cmp(scratch, factory->heap_number_map());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000741 __ j(not_equal, non_float); // argument in edx is not a number -> NaN
742
743 __ bind(&test_other);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000744 __ JumpIfSmi(eax, &done, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000745 __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000746 __ cmp(scratch, factory->heap_number_map());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000747 __ j(not_equal, non_float); // argument in eax is not a number -> NaN
748
749 // Fall-through: Both operands are numbers.
750 __ bind(&done);
751}
752
753
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000754void MathPowStub::Generate(MacroAssembler* masm) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000755 CpuFeatureScope use_sse2(masm, SSE2);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000756 Factory* factory = masm->isolate()->factory();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000757 const Register exponent = eax;
758 const Register base = edx;
759 const Register scratch = ecx;
760 const XMMRegister double_result = xmm3;
761 const XMMRegister double_base = xmm2;
762 const XMMRegister double_exponent = xmm1;
763 const XMMRegister double_scratch = xmm4;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000764
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000765 Label call_runtime, done, exponent_not_smi, int_exponent;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000766
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000767 // Save 1 in double_result - we need this several times later on.
768 __ mov(scratch, Immediate(1));
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000769 __ Cvtsi2sd(double_result, scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000770
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000771 if (exponent_type_ == ON_STACK) {
772 Label base_is_smi, unpack_exponent;
773 // The exponent and base are supplied as arguments on the stack.
774 // This can only happen if the stub is called from non-optimized code.
775 // Load input parameters from stack.
776 __ mov(base, Operand(esp, 2 * kPointerSize));
777 __ mov(exponent, Operand(esp, 1 * kPointerSize));
778
779 __ JumpIfSmi(base, &base_is_smi, Label::kNear);
780 __ cmp(FieldOperand(base, HeapObject::kMapOffset),
781 factory->heap_number_map());
782 __ j(not_equal, &call_runtime);
783
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000784 __ movsd(double_base, FieldOperand(base, HeapNumber::kValueOffset));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000785 __ jmp(&unpack_exponent, Label::kNear);
786
787 __ bind(&base_is_smi);
788 __ SmiUntag(base);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000789 __ Cvtsi2sd(double_base, base);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000790
791 __ bind(&unpack_exponent);
792 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
793 __ SmiUntag(exponent);
794 __ jmp(&int_exponent);
795
796 __ bind(&exponent_not_smi);
797 __ cmp(FieldOperand(exponent, HeapObject::kMapOffset),
798 factory->heap_number_map());
799 __ j(not_equal, &call_runtime);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000800 __ movsd(double_exponent,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000801 FieldOperand(exponent, HeapNumber::kValueOffset));
802 } else if (exponent_type_ == TAGGED) {
803 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
804 __ SmiUntag(exponent);
805 __ jmp(&int_exponent);
806
807 __ bind(&exponent_not_smi);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000808 __ movsd(double_exponent,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000809 FieldOperand(exponent, HeapNumber::kValueOffset));
810 }
811
812 if (exponent_type_ != INTEGER) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000813 Label fast_power, try_arithmetic_simplification;
814 __ DoubleToI(exponent, double_exponent, double_scratch,
815 TREAT_MINUS_ZERO_AS_ZERO, &try_arithmetic_simplification);
816 __ jmp(&int_exponent);
817
818 __ bind(&try_arithmetic_simplification);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000819 // Skip to runtime if possibly NaN (indicated by the indefinite integer).
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000820 __ cvttsd2si(exponent, Operand(double_exponent));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000821 __ cmp(exponent, Immediate(0x80000000u));
822 __ j(equal, &call_runtime);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000823
824 if (exponent_type_ == ON_STACK) {
825 // Detect square root case. Crankshaft detects constant +/-0.5 at
826 // compile time and uses DoMathPowHalf instead. We then skip this check
827 // for non-constant cases of +/-0.5 as these hardly occur.
828 Label continue_sqrt, continue_rsqrt, not_plus_half;
829 // Test for 0.5.
830 // Load double_scratch with 0.5.
831 __ mov(scratch, Immediate(0x3F000000u));
832 __ movd(double_scratch, scratch);
833 __ cvtss2sd(double_scratch, double_scratch);
834 // Already ruled out NaNs for exponent.
835 __ ucomisd(double_scratch, double_exponent);
836 __ j(not_equal, &not_plus_half, Label::kNear);
837
838 // Calculates square root of base. Check for the special case of
839 // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
840 // According to IEEE-754, single-precision -Infinity has the highest
841 // 9 bits set and the lowest 23 bits cleared.
842 __ mov(scratch, 0xFF800000u);
843 __ movd(double_scratch, scratch);
844 __ cvtss2sd(double_scratch, double_scratch);
845 __ ucomisd(double_base, double_scratch);
846 // Comparing -Infinity with NaN results in "unordered", which sets the
847 // zero flag as if both were equal. However, it also sets the carry flag.
848 __ j(not_equal, &continue_sqrt, Label::kNear);
849 __ j(carry, &continue_sqrt, Label::kNear);
850
851 // Set result to Infinity in the special case.
852 __ xorps(double_result, double_result);
853 __ subsd(double_result, double_scratch);
854 __ jmp(&done);
855
856 __ bind(&continue_sqrt);
857 // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
858 __ xorps(double_scratch, double_scratch);
859 __ addsd(double_scratch, double_base); // Convert -0 to +0.
860 __ sqrtsd(double_result, double_scratch);
861 __ jmp(&done);
862
863 // Test for -0.5.
864 __ bind(&not_plus_half);
865 // Load double_exponent with -0.5 by substracting 1.
866 __ subsd(double_scratch, double_result);
867 // Already ruled out NaNs for exponent.
868 __ ucomisd(double_scratch, double_exponent);
869 __ j(not_equal, &fast_power, Label::kNear);
870
871 // Calculates reciprocal of square root of base. Check for the special
872 // case of Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
873 // According to IEEE-754, single-precision -Infinity has the highest
874 // 9 bits set and the lowest 23 bits cleared.
875 __ mov(scratch, 0xFF800000u);
876 __ movd(double_scratch, scratch);
877 __ cvtss2sd(double_scratch, double_scratch);
878 __ ucomisd(double_base, double_scratch);
879 // Comparing -Infinity with NaN results in "unordered", which sets the
880 // zero flag as if both were equal. However, it also sets the carry flag.
881 __ j(not_equal, &continue_rsqrt, Label::kNear);
882 __ j(carry, &continue_rsqrt, Label::kNear);
883
884 // Set result to 0 in the special case.
885 __ xorps(double_result, double_result);
886 __ jmp(&done);
887
888 __ bind(&continue_rsqrt);
889 // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
890 __ xorps(double_exponent, double_exponent);
891 __ addsd(double_exponent, double_base); // Convert -0 to +0.
892 __ sqrtsd(double_exponent, double_exponent);
893 __ divsd(double_result, double_exponent);
894 __ jmp(&done);
895 }
896
897 // Using FPU instructions to calculate power.
898 Label fast_power_failed;
899 __ bind(&fast_power);
900 __ fnclex(); // Clear flags to catch exceptions later.
901 // Transfer (B)ase and (E)xponent onto the FPU register stack.
902 __ sub(esp, Immediate(kDoubleSize));
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000903 __ movsd(Operand(esp, 0), double_exponent);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000904 __ fld_d(Operand(esp, 0)); // E
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000905 __ movsd(Operand(esp, 0), double_base);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000906 __ fld_d(Operand(esp, 0)); // B, E
907
908 // Exponent is in st(1) and base is in st(0)
909 // B ^ E = (2^(E * log2(B)) - 1) + 1 = (2^X - 1) + 1 for X = E * log2(B)
910 // FYL2X calculates st(1) * log2(st(0))
911 __ fyl2x(); // X
912 __ fld(0); // X, X
913 __ frndint(); // rnd(X), X
914 __ fsub(1); // rnd(X), X-rnd(X)
915 __ fxch(1); // X - rnd(X), rnd(X)
916 // F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1
917 __ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X)
918 __ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X)
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000919 __ faddp(1); // 2^(X-rnd(X)), rnd(X)
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000920 // FSCALE calculates st(0) * 2^st(1)
921 __ fscale(); // 2^X, rnd(X)
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000922 __ fstp(1); // 2^X
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000923 // Bail out to runtime in case of exceptions in the status word.
924 __ fnstsw_ax();
925 __ test_b(eax, 0x5F); // We check for all but precision exception.
926 __ j(not_zero, &fast_power_failed, Label::kNear);
927 __ fstp_d(Operand(esp, 0));
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000928 __ movsd(double_result, Operand(esp, 0));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000929 __ add(esp, Immediate(kDoubleSize));
930 __ jmp(&done);
931
932 __ bind(&fast_power_failed);
933 __ fninit();
934 __ add(esp, Immediate(kDoubleSize));
935 __ jmp(&call_runtime);
936 }
937
938 // Calculate power with integer exponent.
939 __ bind(&int_exponent);
940 const XMMRegister double_scratch2 = double_exponent;
941 __ mov(scratch, exponent); // Back up exponent.
942 __ movsd(double_scratch, double_base); // Back up base.
943 __ movsd(double_scratch2, double_result); // Load double_exponent with 1.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000944
945 // Get absolute value of exponent.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000946 Label no_neg, while_true, while_false;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000947 __ test(scratch, scratch);
948 __ j(positive, &no_neg, Label::kNear);
949 __ neg(scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000950 __ bind(&no_neg);
951
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000952 __ j(zero, &while_false, Label::kNear);
953 __ shr(scratch, 1);
954 // Above condition means CF==0 && ZF==0. This means that the
955 // bit that has been shifted out is 0 and the result is not 0.
956 __ j(above, &while_true, Label::kNear);
957 __ movsd(double_result, double_scratch);
958 __ j(zero, &while_false, Label::kNear);
959
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000960 __ bind(&while_true);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000961 __ shr(scratch, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000962 __ mulsd(double_scratch, double_scratch);
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000963 __ j(above, &while_true, Label::kNear);
964 __ mulsd(double_result, double_scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000965 __ j(not_zero, &while_true);
966
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000967 __ bind(&while_false);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000968 // scratch has the original value of the exponent - if the exponent is
969 // negative, return 1/result.
970 __ test(exponent, exponent);
971 __ j(positive, &done);
972 __ divsd(double_scratch2, double_result);
973 __ movsd(double_result, double_scratch2);
974 // Test whether result is zero. Bail out to check for subnormal result.
975 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
976 __ xorps(double_scratch2, double_scratch2);
977 __ ucomisd(double_scratch2, double_result); // Result cannot be NaN.
978 // double_exponent aliased as double_scratch2 has already been overwritten
979 // and may not have contained the exponent value in the first place when the
980 // exponent is a smi. We reset it with exponent value before bailing out.
981 __ j(not_equal, &done);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000982 __ Cvtsi2sd(double_exponent, exponent);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000983
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000984 // Returning or bailing out.
985 Counters* counters = masm->isolate()->counters();
986 if (exponent_type_ == ON_STACK) {
987 // The arguments are still on the stack.
988 __ bind(&call_runtime);
989 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000990
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000991 // The stub is called from non-optimized code, which expects the result
992 // as heap number in exponent.
993 __ bind(&done);
994 __ AllocateHeapNumber(eax, scratch, base, &call_runtime);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000995 __ movsd(FieldOperand(eax, HeapNumber::kValueOffset), double_result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000996 __ IncrementCounter(counters->math_pow(), 1);
997 __ ret(2 * kPointerSize);
998 } else {
999 __ bind(&call_runtime);
1000 {
1001 AllowExternalCallThatCantCauseGC scope(masm);
1002 __ PrepareCallCFunction(4, scratch);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00001003 __ movsd(Operand(esp, 0 * kDoubleSize), double_base);
1004 __ movsd(Operand(esp, 1 * kDoubleSize), double_exponent);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001005 __ CallCFunction(
1006 ExternalReference::power_double_double_function(masm->isolate()), 4);
1007 }
1008 // Return value is in st(0) on ia32.
1009 // Store it into the (fixed) result register.
1010 __ sub(esp, Immediate(kDoubleSize));
1011 __ fstp_d(Operand(esp, 0));
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00001012 __ movsd(double_result, Operand(esp, 0));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001013 __ add(esp, Immediate(kDoubleSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001014
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001015 __ bind(&done);
1016 __ IncrementCounter(counters->math_pow(), 1);
1017 __ ret(0);
1018 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001019}
1020
1021
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001022void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
1023 // ----------- S t a t e -------------
1024 // -- ecx : name
1025 // -- edx : receiver
1026 // -- esp[0] : return address
1027 // -----------------------------------
1028 Label miss;
1029
1030 if (kind() == Code::KEYED_LOAD_IC) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001031 __ cmp(ecx, Immediate(masm->isolate()->factory()->prototype_string()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001032 __ j(not_equal, &miss);
1033 }
1034
1035 StubCompiler::GenerateLoadFunctionPrototype(masm, edx, eax, ebx, &miss);
1036 __ bind(&miss);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001037 StubCompiler::TailCallBuiltin(
1038 masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001039}
1040
1041
1042void StringLengthStub::Generate(MacroAssembler* masm) {
1043 // ----------- S t a t e -------------
1044 // -- ecx : name
1045 // -- edx : receiver
1046 // -- esp[0] : return address
1047 // -----------------------------------
1048 Label miss;
1049
1050 if (kind() == Code::KEYED_LOAD_IC) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001051 __ cmp(ecx, Immediate(masm->isolate()->factory()->length_string()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001052 __ j(not_equal, &miss);
1053 }
1054
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001055 StubCompiler::GenerateLoadStringLength(masm, edx, eax, ebx, &miss);
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001056 __ bind(&miss);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001057 StubCompiler::TailCallBuiltin(
1058 masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001059}
1060
1061
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001062void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
1063 // ----------- S t a t e -------------
1064 // -- eax : value
1065 // -- ecx : name
1066 // -- edx : receiver
1067 // -- esp[0] : return address
1068 // -----------------------------------
1069 //
1070 // This accepts as a receiver anything JSArray::SetElementsLength accepts
1071 // (currently anything except for external arrays which means anything with
1072 // elements of FixedArray type). Value must be a number, but only smis are
1073 // accepted as the most common case.
1074
1075 Label miss;
1076
1077 Register receiver = edx;
1078 Register value = eax;
1079 Register scratch = ebx;
1080
ulan@chromium.org750145a2013-03-07 15:14:13 +00001081 if (kind() == Code::KEYED_STORE_IC) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001082 __ cmp(ecx, Immediate(masm->isolate()->factory()->length_string()));
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001083 __ j(not_equal, &miss);
1084 }
1085
1086 // Check that the receiver isn't a smi.
1087 __ JumpIfSmi(receiver, &miss);
1088
1089 // Check that the object is a JS array.
1090 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
1091 __ j(not_equal, &miss);
1092
1093 // Check that elements are FixedArray.
1094 // We rely on StoreIC_ArrayLength below to deal with all types of
1095 // fast elements (including COW).
1096 __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
1097 __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
1098 __ j(not_equal, &miss);
1099
1100 // Check that the array has fast properties, otherwise the length
1101 // property might have been redefined.
1102 __ mov(scratch, FieldOperand(receiver, JSArray::kPropertiesOffset));
1103 __ CompareRoot(FieldOperand(scratch, FixedArray::kMapOffset),
1104 Heap::kHashTableMapRootIndex);
1105 __ j(equal, &miss);
1106
1107 // Check that value is a smi.
1108 __ JumpIfNotSmi(value, &miss);
1109
1110 // Prepare tail call to StoreIC_ArrayLength.
1111 __ pop(scratch);
1112 __ push(receiver);
1113 __ push(value);
1114 __ push(scratch); // return address
1115
1116 ExternalReference ref =
1117 ExternalReference(IC_Utility(IC::kStoreIC_ArrayLength), masm->isolate());
1118 __ TailCallExternalReference(ref, 2, 1);
1119
1120 __ bind(&miss);
1121
danno@chromium.orgbee51992013-07-10 14:57:15 +00001122 StubCompiler::TailCallBuiltin(
1123 masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001124}
1125
1126
ricow@chromium.org65fae842010-08-25 15:26:24 +00001127void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
1128 // The key is in edx and the parameter count is in eax.
1129
1130 // The displacement is used for skipping the frame pointer on the
1131 // stack. It is the offset of the last parameter (if any) relative
1132 // to the frame pointer.
1133 static const int kDisplacement = 1 * kPointerSize;
1134
1135 // Check that the key is a smi.
1136 Label slow;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001137 __ JumpIfNotSmi(edx, &slow, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001138
1139 // Check if the calling frame is an arguments adaptor frame.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001140 Label adaptor;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001141 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1142 __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001143 __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001144 __ j(equal, &adaptor, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001145
1146 // Check index against formal parameters count limit passed in
1147 // through register eax. Use unsigned comparison to get negative
1148 // check for free.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001149 __ cmp(edx, eax);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001150 __ j(above_equal, &slow, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001151
1152 // Read the argument from the stack and return it.
1153 STATIC_ASSERT(kSmiTagSize == 1);
1154 STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these.
1155 __ lea(ebx, Operand(ebp, eax, times_2, 0));
1156 __ neg(edx);
1157 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
1158 __ ret(0);
1159
1160 // Arguments adaptor case: Check index against actual arguments
1161 // limit found in the arguments adaptor frame. Use unsigned
1162 // comparison to get negative check for free.
1163 __ bind(&adaptor);
1164 __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001165 __ cmp(edx, ecx);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001166 __ j(above_equal, &slow, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001167
1168 // Read the argument from the stack and return it.
1169 STATIC_ASSERT(kSmiTagSize == 1);
1170 STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these.
1171 __ lea(ebx, Operand(ebx, ecx, times_2, 0));
1172 __ neg(edx);
1173 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
1174 __ ret(0);
1175
1176 // Slow-case: Handle non-smi or out-of-bounds access to arguments
1177 // by calling the runtime system.
1178 __ bind(&slow);
1179 __ pop(ebx); // Return address.
1180 __ push(edx);
1181 __ push(ebx);
1182 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
1183}
1184
1185
whesse@chromium.org7b260152011-06-20 15:33:18 +00001186void ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001187 // esp[0] : return address
1188 // esp[4] : number of parameters
1189 // esp[8] : receiver displacement
whesse@chromium.org7b260152011-06-20 15:33:18 +00001190 // esp[12] : function
ricow@chromium.org65fae842010-08-25 15:26:24 +00001191
whesse@chromium.org7b260152011-06-20 15:33:18 +00001192 // Check if the calling frame is an arguments adaptor frame.
1193 Label runtime;
1194 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1195 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001196 __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001197 __ j(not_equal, &runtime, Label::kNear);
1198
1199 // Patch the arguments.length and the parameters pointer.
1200 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
1201 __ mov(Operand(esp, 1 * kPointerSize), ecx);
1202 __ lea(edx, Operand(edx, ecx, times_2,
1203 StandardFrameConstants::kCallerSPOffset));
1204 __ mov(Operand(esp, 2 * kPointerSize), edx);
1205
1206 __ bind(&runtime);
1207 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
1208}
1209
1210
1211void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001212 Isolate* isolate = masm->isolate();
1213
whesse@chromium.org7b260152011-06-20 15:33:18 +00001214 // esp[0] : return address
1215 // esp[4] : number of parameters (tagged)
1216 // esp[8] : receiver displacement
1217 // esp[12] : function
1218
1219 // ebx = parameter count (tagged)
1220 __ mov(ebx, Operand(esp, 1 * kPointerSize));
1221
1222 // Check if the calling frame is an arguments adaptor frame.
1223 // TODO(rossberg): Factor out some of the bits that are shared with the other
1224 // Generate* functions.
1225 Label runtime;
1226 Label adaptor_frame, try_allocate;
1227 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1228 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001229 __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001230 __ j(equal, &adaptor_frame, Label::kNear);
1231
1232 // No adaptor, parameter count = argument count.
1233 __ mov(ecx, ebx);
1234 __ jmp(&try_allocate, Label::kNear);
1235
1236 // We have an adaptor frame. Patch the parameters pointer.
1237 __ bind(&adaptor_frame);
1238 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
1239 __ lea(edx, Operand(edx, ecx, times_2,
1240 StandardFrameConstants::kCallerSPOffset));
1241 __ mov(Operand(esp, 2 * kPointerSize), edx);
1242
1243 // ebx = parameter count (tagged)
1244 // ecx = argument count (tagged)
1245 // esp[4] = parameter count (tagged)
1246 // esp[8] = address of receiver argument
1247 // Compute the mapped parameter count = min(ebx, ecx) in ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001248 __ cmp(ebx, ecx);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001249 __ j(less_equal, &try_allocate, Label::kNear);
1250 __ mov(ebx, ecx);
1251
1252 __ bind(&try_allocate);
1253
1254 // Save mapped parameter count.
1255 __ push(ebx);
1256
1257 // Compute the sizes of backing store, parameter map, and arguments object.
1258 // 1. Parameter map, has 2 extra words containing context and backing store.
1259 const int kParameterMapHeaderSize =
1260 FixedArray::kHeaderSize + 2 * kPointerSize;
1261 Label no_parameter_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001262 __ test(ebx, ebx);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001263 __ j(zero, &no_parameter_map, Label::kNear);
1264 __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize));
1265 __ bind(&no_parameter_map);
1266
1267 // 2. Backing store.
1268 __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize));
1269
1270 // 3. Arguments object.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001271 __ add(ebx, Immediate(Heap::kArgumentsObjectSize));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001272
1273 // Do the allocation of all three objects in one go.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001274 __ Allocate(ebx, eax, edx, edi, &runtime, TAG_OBJECT);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001275
1276 // eax = address of new object(s) (tagged)
1277 // ecx = argument count (tagged)
1278 // esp[0] = mapped parameter count (tagged)
1279 // esp[8] = parameter count (tagged)
1280 // esp[12] = address of receiver argument
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001281 // Get the arguments boilerplate from the current native context into edi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001282 Label has_mapped_parameters, copy;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001283 __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
1284 __ mov(edi, FieldOperand(edi, GlobalObject::kNativeContextOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001285 __ mov(ebx, Operand(esp, 0 * kPointerSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001286 __ test(ebx, ebx);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001287 __ j(not_zero, &has_mapped_parameters, Label::kNear);
1288 __ mov(edi, Operand(edi,
1289 Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX)));
1290 __ jmp(&copy, Label::kNear);
1291
1292 __ bind(&has_mapped_parameters);
1293 __ mov(edi, Operand(edi,
1294 Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX)));
1295 __ bind(&copy);
1296
1297 // eax = address of new object (tagged)
1298 // ebx = mapped parameter count (tagged)
1299 // ecx = argument count (tagged)
1300 // edi = address of boilerplate object (tagged)
1301 // esp[0] = mapped parameter count (tagged)
1302 // esp[8] = parameter count (tagged)
1303 // esp[12] = address of receiver argument
1304 // Copy the JS object part.
1305 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
1306 __ mov(edx, FieldOperand(edi, i));
1307 __ mov(FieldOperand(eax, i), edx);
1308 }
1309
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001310 // Set up the callee in-object property.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001311 STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
1312 __ mov(edx, Operand(esp, 4 * kPointerSize));
1313 __ mov(FieldOperand(eax, JSObject::kHeaderSize +
1314 Heap::kArgumentsCalleeIndex * kPointerSize),
1315 edx);
1316
1317 // Use the length (smi tagged) and set that as an in-object property too.
1318 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
1319 __ mov(FieldOperand(eax, JSObject::kHeaderSize +
1320 Heap::kArgumentsLengthIndex * kPointerSize),
1321 ecx);
1322
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001323 // Set up the elements pointer in the allocated arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001324 // If we allocated a parameter map, edi will point there, otherwise to the
1325 // backing store.
1326 __ lea(edi, Operand(eax, Heap::kArgumentsObjectSize));
1327 __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
1328
1329 // eax = address of new object (tagged)
1330 // ebx = mapped parameter count (tagged)
1331 // ecx = argument count (tagged)
1332 // edi = address of parameter map or backing store (tagged)
1333 // esp[0] = mapped parameter count (tagged)
1334 // esp[8] = parameter count (tagged)
1335 // esp[12] = address of receiver argument
1336 // Free a register.
1337 __ push(eax);
1338
1339 // Initialize parameter map. If there are no mapped arguments, we're done.
1340 Label skip_parameter_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001341 __ test(ebx, ebx);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001342 __ j(zero, &skip_parameter_map);
1343
1344 __ mov(FieldOperand(edi, FixedArray::kMapOffset),
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001345 Immediate(isolate->factory()->non_strict_arguments_elements_map()));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001346 __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2))));
1347 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax);
1348 __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi);
1349 __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize));
1350 __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax);
1351
1352 // Copy the parameter slots and the holes in the arguments.
1353 // We need to fill in mapped_parameter_count slots. They index the context,
1354 // where parameters are stored in reverse order, at
1355 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1
1356 // The mapped parameter thus need to get indices
1357 // MIN_CONTEXT_SLOTS+parameter_count-1 ..
1358 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count
1359 // We loop from right to left.
1360 Label parameters_loop, parameters_test;
1361 __ push(ecx);
1362 __ mov(eax, Operand(esp, 2 * kPointerSize));
1363 __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS)));
1364 __ add(ebx, Operand(esp, 4 * kPointerSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001365 __ sub(ebx, eax);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001366 __ mov(ecx, isolate->factory()->the_hole_value());
whesse@chromium.org7b260152011-06-20 15:33:18 +00001367 __ mov(edx, edi);
1368 __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize));
1369 // eax = loop variable (tagged)
1370 // ebx = mapping index (tagged)
1371 // ecx = the hole value
1372 // edx = address of parameter map (tagged)
1373 // edi = address of backing store (tagged)
1374 // esp[0] = argument count (tagged)
1375 // esp[4] = address of new object (tagged)
1376 // esp[8] = mapped parameter count (tagged)
1377 // esp[16] = parameter count (tagged)
1378 // esp[20] = address of receiver argument
1379 __ jmp(&parameters_test, Label::kNear);
1380
1381 __ bind(&parameters_loop);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001382 __ sub(eax, Immediate(Smi::FromInt(1)));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001383 __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx);
1384 __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001385 __ add(ebx, Immediate(Smi::FromInt(1)));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001386 __ bind(&parameters_test);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001387 __ test(eax, eax);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001388 __ j(not_zero, &parameters_loop, Label::kNear);
1389 __ pop(ecx);
1390
1391 __ bind(&skip_parameter_map);
1392
1393 // ecx = argument count (tagged)
1394 // edi = address of backing store (tagged)
1395 // esp[0] = address of new object (tagged)
1396 // esp[4] = mapped parameter count (tagged)
1397 // esp[12] = parameter count (tagged)
1398 // esp[16] = address of receiver argument
1399 // Copy arguments header and remaining slots (if there are any).
1400 __ mov(FieldOperand(edi, FixedArray::kMapOffset),
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001401 Immediate(isolate->factory()->fixed_array_map()));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001402 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
1403
1404 Label arguments_loop, arguments_test;
1405 __ mov(ebx, Operand(esp, 1 * kPointerSize));
1406 __ mov(edx, Operand(esp, 4 * kPointerSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001407 __ sub(edx, ebx); // Is there a smarter way to do negative scaling?
1408 __ sub(edx, ebx);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001409 __ jmp(&arguments_test, Label::kNear);
1410
1411 __ bind(&arguments_loop);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001412 __ sub(edx, Immediate(kPointerSize));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001413 __ mov(eax, Operand(edx, 0));
1414 __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001415 __ add(ebx, Immediate(Smi::FromInt(1)));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001416
1417 __ bind(&arguments_test);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001418 __ cmp(ebx, ecx);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001419 __ j(less, &arguments_loop, Label::kNear);
1420
1421 // Restore.
1422 __ pop(eax); // Address of arguments object.
1423 __ pop(ebx); // Parameter count.
1424
1425 // Return and remove the on-stack parameters.
1426 __ ret(3 * kPointerSize);
1427
1428 // Do the runtime call to allocate the arguments object.
1429 __ bind(&runtime);
1430 __ pop(eax); // Remove saved parameter count.
1431 __ mov(Operand(esp, 1 * kPointerSize), ecx); // Patch argument count.
danno@chromium.org72204d52012-10-31 10:02:10 +00001432 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001433}
1434
1435
1436void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001437 Isolate* isolate = masm->isolate();
1438
whesse@chromium.org7b260152011-06-20 15:33:18 +00001439 // esp[0] : return address
1440 // esp[4] : number of parameters
1441 // esp[8] : receiver displacement
1442 // esp[12] : function
ricow@chromium.org65fae842010-08-25 15:26:24 +00001443
1444 // Check if the calling frame is an arguments adaptor frame.
1445 Label adaptor_frame, try_allocate, runtime;
1446 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1447 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001448 __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001449 __ j(equal, &adaptor_frame, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001450
1451 // Get the length from the frame.
1452 __ mov(ecx, Operand(esp, 1 * kPointerSize));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001453 __ jmp(&try_allocate, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001454
1455 // Patch the arguments.length and the parameters pointer.
1456 __ bind(&adaptor_frame);
1457 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
1458 __ mov(Operand(esp, 1 * kPointerSize), ecx);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001459 __ lea(edx, Operand(edx, ecx, times_2,
1460 StandardFrameConstants::kCallerSPOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001461 __ mov(Operand(esp, 2 * kPointerSize), edx);
1462
1463 // Try the new space allocation. Start out with computing the size of
1464 // the arguments object and the elements array.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001465 Label add_arguments_object;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001466 __ bind(&try_allocate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001467 __ test(ecx, ecx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001468 __ j(zero, &add_arguments_object, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001469 __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize));
1470 __ bind(&add_arguments_object);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001471 __ add(ecx, Immediate(Heap::kArgumentsObjectSizeStrict));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001472
1473 // Do the allocation of both objects in one go.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001474 __ Allocate(ecx, eax, edx, ebx, &runtime, TAG_OBJECT);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001475
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001476 // Get the arguments boilerplate from the current native context.
1477 __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
1478 __ mov(edi, FieldOperand(edi, GlobalObject::kNativeContextOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001479 const int offset =
1480 Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX);
1481 __ mov(edi, Operand(edi, offset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001482
1483 // Copy the JS object part.
1484 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
1485 __ mov(ebx, FieldOperand(edi, i));
1486 __ mov(FieldOperand(eax, i), ebx);
1487 }
1488
ricow@chromium.org65fae842010-08-25 15:26:24 +00001489 // Get the length (smi tagged) and set that as an in-object property too.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001490 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001491 __ mov(ecx, Operand(esp, 1 * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001492 __ mov(FieldOperand(eax, JSObject::kHeaderSize +
whesse@chromium.org7b260152011-06-20 15:33:18 +00001493 Heap::kArgumentsLengthIndex * kPointerSize),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001494 ecx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001495
1496 // If there are no actual arguments, we're done.
1497 Label done;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001498 __ test(ecx, ecx);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001499 __ j(zero, &done, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001500
1501 // Get the parameters pointer from the stack.
1502 __ mov(edx, Operand(esp, 2 * kPointerSize));
1503
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001504 // Set up the elements pointer in the allocated arguments object and
ricow@chromium.org65fae842010-08-25 15:26:24 +00001505 // initialize the header in the elements fixed array.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001506 __ lea(edi, Operand(eax, Heap::kArgumentsObjectSizeStrict));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001507 __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
1508 __ mov(FieldOperand(edi, FixedArray::kMapOffset),
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001509 Immediate(isolate->factory()->fixed_array_map()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001510
ricow@chromium.org65fae842010-08-25 15:26:24 +00001511 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
1512 // Untag the length for the loop below.
1513 __ SmiUntag(ecx);
1514
1515 // Copy the fixed array slots.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001516 Label loop;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001517 __ bind(&loop);
1518 __ mov(ebx, Operand(edx, -1 * kPointerSize)); // Skip receiver.
1519 __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001520 __ add(edi, Immediate(kPointerSize));
1521 __ sub(edx, Immediate(kPointerSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001522 __ dec(ecx);
1523 __ j(not_zero, &loop);
1524
1525 // Return and remove the on-stack parameters.
1526 __ bind(&done);
1527 __ ret(3 * kPointerSize);
1528
1529 // Do the runtime call to allocate the arguments object.
1530 __ bind(&runtime);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001531 __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001532}
1533
1534
1535void RegExpExecStub::Generate(MacroAssembler* masm) {
1536 // Just jump directly to runtime if native RegExp is not selected at compile
1537 // time or if regexp entry in generated code is turned off runtime switch or
1538 // at compilation.
1539#ifdef V8_INTERPRETED_REGEXP
1540 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
1541#else // V8_INTERPRETED_REGEXP
ricow@chromium.org65fae842010-08-25 15:26:24 +00001542
1543 // Stack frame on entry.
1544 // esp[0]: return address
1545 // esp[4]: last_match_info (expected JSArray)
1546 // esp[8]: previous index
1547 // esp[12]: subject string
1548 // esp[16]: JSRegExp object
1549
1550 static const int kLastMatchInfoOffset = 1 * kPointerSize;
1551 static const int kPreviousIndexOffset = 2 * kPointerSize;
1552 static const int kSubjectOffset = 3 * kPointerSize;
1553 static const int kJSRegExpOffset = 4 * kPointerSize;
1554
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001555 Label runtime;
1556 Factory* factory = masm->isolate()->factory();
ricow@chromium.org65fae842010-08-25 15:26:24 +00001557
1558 // Ensure that a RegExp stack is allocated.
1559 ExternalReference address_of_regexp_stack_memory_address =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001560 ExternalReference::address_of_regexp_stack_memory_address(
1561 masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001562 ExternalReference address_of_regexp_stack_memory_size =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001563 ExternalReference::address_of_regexp_stack_memory_size(masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001564 __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001565 __ test(ebx, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001566 __ j(zero, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001567
1568 // Check that the first argument is a JSRegExp object.
1569 __ mov(eax, Operand(esp, kJSRegExpOffset));
1570 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001571 __ JumpIfSmi(eax, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001572 __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx);
1573 __ j(not_equal, &runtime);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001574
ricow@chromium.org65fae842010-08-25 15:26:24 +00001575 // Check that the RegExp has been compiled (data contains a fixed array).
1576 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset));
1577 if (FLAG_debug_code) {
1578 __ test(ecx, Immediate(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +00001579 __ Check(not_zero, kUnexpectedTypeForRegExpDataFixedArrayExpected);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001580 __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx);
danno@chromium.org59400602013-08-13 17:09:37 +00001581 __ Check(equal, kUnexpectedTypeForRegExpDataFixedArrayExpected);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001582 }
1583
1584 // ecx: RegExp data (FixedArray)
1585 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
1586 __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001587 __ cmp(ebx, Immediate(Smi::FromInt(JSRegExp::IRREGEXP)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001588 __ j(not_equal, &runtime);
1589
1590 // ecx: RegExp data (FixedArray)
1591 // Check that the number of captures fit in the static offsets vector buffer.
1592 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001593 // Check (number_of_captures + 1) * 2 <= offsets vector size
1594 // Or number_of_captures * 2 <= offsets vector size - 2
1595 // Multiplying by 2 comes for free since edx is smi-tagged.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001596 STATIC_ASSERT(kSmiTag == 0);
1597 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001598 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2);
1599 __ cmp(edx, Isolate::kJSRegexpStaticOffsetsVectorSize - 2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001600 __ j(above, &runtime);
1601
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001602 // Reset offset for possibly sliced string.
1603 __ Set(edi, Immediate(0));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001604 __ mov(eax, Operand(esp, kSubjectOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001605 __ JumpIfSmi(eax, &runtime);
1606 __ mov(edx, eax); // Make a copy of the original subject string.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001607 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
1608 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001609
1610 // eax: subject string
1611 // edx: subject string
1612 // ebx: subject string instance type
1613 // ecx: RegExp data (FixedArray)
1614 // Handle subject string according to its encoding and representation:
1615 // (1) Sequential two byte? If yes, go to (9).
1616 // (2) Sequential one byte? If yes, go to (6).
1617 // (3) Anything but sequential or cons? If yes, go to (7).
1618 // (4) Cons string. If the string is flat, replace subject with first string.
1619 // Otherwise bailout.
1620 // (5a) Is subject sequential two byte? If yes, go to (9).
1621 // (5b) Is subject external? If yes, go to (8).
1622 // (6) One byte sequential. Load regexp code for one byte.
1623 // (E) Carry on.
1624 /// [...]
1625
1626 // Deferred code at the end of the stub:
1627 // (7) Not a long external string? If yes, go to (10).
1628 // (8) External string. Make it, offset-wise, look like a sequential string.
1629 // (8a) Is the external string one byte? If yes, go to (6).
1630 // (9) Two byte sequential. Load regexp code for one byte. Go to (E).
1631 // (10) Short external string or not a string? If yes, bail out to runtime.
1632 // (11) Sliced string. Replace subject with parent. Go to (5a).
1633
1634 Label seq_one_byte_string /* 6 */, seq_two_byte_string /* 9 */,
1635 external_string /* 8 */, check_underlying /* 5a */,
1636 not_seq_nor_cons /* 7 */, check_code /* E */,
1637 not_long_external /* 10 */;
1638
1639 // (1) Sequential two byte? If yes, go to (9).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001640 __ and_(ebx, kIsNotStringMask |
1641 kStringRepresentationMask |
1642 kStringEncodingMask |
1643 kShortExternalStringMask);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001644 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001645 __ j(zero, &seq_two_byte_string); // Go to (9).
1646
1647 // (2) Sequential one byte? If yes, go to (6).
1648 // Any other sequential string must be one byte.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001649 __ and_(ebx, Immediate(kIsNotStringMask |
1650 kStringRepresentationMask |
1651 kShortExternalStringMask));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001652 __ j(zero, &seq_one_byte_string, Label::kNear); // Go to (6).
ricow@chromium.org65fae842010-08-25 15:26:24 +00001653
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001654 // (3) Anything but sequential or cons? If yes, go to (7).
1655 // We check whether the subject string is a cons, since sequential strings
1656 // have already been covered.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001657 STATIC_ASSERT(kConsStringTag < kExternalStringTag);
1658 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001659 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag);
1660 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001661 __ cmp(ebx, Immediate(kExternalStringTag));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001662 __ j(greater_equal, &not_seq_nor_cons); // Go to (7).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001663
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001664 // (4) Cons string. Check that it's flat.
1665 // Replace subject with first string and reload instance type.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001666 __ cmp(FieldOperand(eax, ConsString::kSecondOffset), factory->empty_string());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001667 __ j(not_equal, &runtime);
1668 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001669 __ bind(&check_underlying);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001670 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001671 __ mov(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1672
1673 // (5a) Is subject sequential two byte? If yes, go to (9).
1674 __ test_b(ebx, kStringRepresentationMask | kStringEncodingMask);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001675 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001676 __ j(zero, &seq_two_byte_string); // Go to (9).
1677 // (5b) Is subject external? If yes, go to (8).
1678 __ test_b(ebx, kStringRepresentationMask);
1679 // The underlying external string is never a short external string.
1680 STATIC_CHECK(ExternalString::kMaxShortLength < ConsString::kMinLength);
1681 STATIC_CHECK(ExternalString::kMaxShortLength < SlicedString::kMinLength);
1682 __ j(not_zero, &external_string); // Go to (8).
ricow@chromium.org65fae842010-08-25 15:26:24 +00001683
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001684 // eax: sequential subject string (or look-alike, external string)
1685 // edx: original subject string
ricow@chromium.org65fae842010-08-25 15:26:24 +00001686 // ecx: RegExp data (FixedArray)
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001687 // (6) One byte sequential. Load regexp code for one byte.
1688 __ bind(&seq_one_byte_string);
1689 // Load previous index and check range before edx is overwritten. We have
1690 // to use edx instead of eax here because it might have been only made to
1691 // look like a sequential string when it actually is an external string.
1692 __ mov(ebx, Operand(esp, kPreviousIndexOffset));
1693 __ JumpIfNotSmi(ebx, &runtime);
1694 __ cmp(ebx, FieldOperand(edx, String::kLengthOffset));
1695 __ j(above_equal, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001696 __ mov(edx, FieldOperand(ecx, JSRegExp::kDataAsciiCodeOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001697 __ Set(ecx, Immediate(1)); // Type is one byte.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001698
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001699 // (E) Carry on. String handling is done.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001700 __ bind(&check_code);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001701 // edx: irregexp code
ricow@chromium.org65fae842010-08-25 15:26:24 +00001702 // Check that the irregexp code has been generated for the actual string
1703 // encoding. If it has, the field contains a code object otherwise it contains
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001704 // a smi (code flushing support).
1705 __ JumpIfSmi(edx, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001706
1707 // eax: subject string
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001708 // ebx: previous index (smi)
ricow@chromium.org65fae842010-08-25 15:26:24 +00001709 // edx: code
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001710 // ecx: encoding of subject string (1 if ASCII, 0 if two_byte);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001711 // All checks done. Now push arguments for native regexp code.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001712 Counters* counters = masm->isolate()->counters();
1713 __ IncrementCounter(counters->regexp_entry_native(), 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001714
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001715 // Isolates: note we add an additional parameter here (isolate pointer).
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001716 static const int kRegExpExecuteArguments = 9;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001717 __ EnterApiExitFrame(kRegExpExecuteArguments);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001718
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001719 // Argument 9: Pass current isolate address.
1720 __ mov(Operand(esp, 8 * kPointerSize),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001721 Immediate(ExternalReference::isolate_address(masm->isolate())));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001722
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001723 // Argument 8: Indicate that this is a direct call from JavaScript.
1724 __ mov(Operand(esp, 7 * kPointerSize), Immediate(1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001725
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001726 // Argument 7: Start (high end) of backtracking stack memory area.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001727 __ mov(esi, Operand::StaticVariable(address_of_regexp_stack_memory_address));
1728 __ add(esi, Operand::StaticVariable(address_of_regexp_stack_memory_size));
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001729 __ mov(Operand(esp, 6 * kPointerSize), esi);
1730
1731 // Argument 6: Set the number of capture registers to zero to force global
1732 // regexps to behave as non-global. This does not affect non-global regexps.
1733 __ mov(Operand(esp, 5 * kPointerSize), Immediate(0));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001734
1735 // Argument 5: static offsets vector buffer.
1736 __ mov(Operand(esp, 4 * kPointerSize),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001737 Immediate(ExternalReference::address_of_static_offsets_vector(
1738 masm->isolate())));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001739
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001740 // Argument 2: Previous index.
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001741 __ SmiUntag(ebx);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001742 __ mov(Operand(esp, 1 * kPointerSize), ebx);
1743
1744 // Argument 1: Original subject string.
1745 // The original subject is in the previous stack frame. Therefore we have to
1746 // use ebp, which points exactly to one pointer size below the previous esp.
1747 // (Because creating a new stack frame pushes the previous ebp onto the stack
1748 // and thereby moves up esp by one kPointerSize.)
1749 __ mov(esi, Operand(ebp, kSubjectOffset + kPointerSize));
1750 __ mov(Operand(esp, 0 * kPointerSize), esi);
1751
1752 // esi: original subject string
1753 // eax: underlying subject string
1754 // ebx: previous index
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001755 // ecx: encoding of subject string (1 if ASCII 0 if two_byte);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001756 // edx: code
ricow@chromium.org65fae842010-08-25 15:26:24 +00001757 // Argument 4: End of string data
1758 // Argument 3: Start of string data
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001759 // Prepare start and end index of the input.
1760 // Load the length from the original sliced string if that is the case.
1761 __ mov(esi, FieldOperand(esi, String::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001762 __ add(esi, edi); // Calculate input end wrt offset.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001763 __ SmiUntag(edi);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001764 __ add(ebx, edi); // Calculate input start wrt offset.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001765
1766 // ebx: start index of the input string
1767 // esi: end index of the input string
1768 Label setup_two_byte, setup_rest;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001769 __ test(ecx, ecx);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001770 __ j(zero, &setup_two_byte, Label::kNear);
1771 __ SmiUntag(esi);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001772 __ lea(ecx, FieldOperand(eax, esi, times_1, SeqOneByteString::kHeaderSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001773 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001774 __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqOneByteString::kHeaderSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001775 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001776 __ jmp(&setup_rest, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001777
1778 __ bind(&setup_two_byte);
1779 STATIC_ASSERT(kSmiTag == 0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001780 STATIC_ASSERT(kSmiTagSize == 1); // esi is smi (powered by 2).
1781 __ lea(ecx, FieldOperand(eax, esi, times_1, SeqTwoByteString::kHeaderSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001782 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4.
1783 __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize));
1784 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3.
1785
1786 __ bind(&setup_rest);
1787
ricow@chromium.org65fae842010-08-25 15:26:24 +00001788 // Locate the code entry and call it.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001789 __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
1790 __ call(edx);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001791
1792 // Drop arguments and come back to JS mode.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001793 __ LeaveApiExitFrame(true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001794
1795 // Check the result.
1796 Label success;
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001797 __ cmp(eax, 1);
1798 // We expect exactly one result since we force the called regexp to behave
1799 // as non-global.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001800 __ j(equal, &success);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001801 Label failure;
1802 __ cmp(eax, NativeRegExpMacroAssembler::FAILURE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001803 __ j(equal, &failure);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001804 __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION);
1805 // If not exception it can only be retry. Handle that in the runtime system.
1806 __ j(not_equal, &runtime);
1807 // Result must now be exception. If there is no pending exception already a
1808 // stack overflow (on the backtrack stack) was detected in RegExp code but
1809 // haven't created the exception yet. Handle that in the runtime system.
1810 // TODO(592): Rerunning the RegExp to get the stack overflow exception.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001811 ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001812 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001813 __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001814 __ mov(eax, Operand::StaticVariable(pending_exception));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001815 __ cmp(edx, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001816 __ j(equal, &runtime);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001817 // For exception, throw the exception again.
1818
1819 // Clear the pending exception variable.
1820 __ mov(Operand::StaticVariable(pending_exception), edx);
1821
1822 // Special handling of termination exceptions which are uncatchable
1823 // by javascript code.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001824 __ cmp(eax, factory->termination_exception());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001825 Label throw_termination_exception;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001826 __ j(equal, &throw_termination_exception, Label::kNear);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001827
1828 // Handle normal exception by following handler chain.
1829 __ Throw(eax);
1830
1831 __ bind(&throw_termination_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001832 __ ThrowUncatchable(eax);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001833
ricow@chromium.org65fae842010-08-25 15:26:24 +00001834 __ bind(&failure);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001835 // For failure to match, return null.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001836 __ mov(eax, factory->null_value());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001837 __ ret(4 * kPointerSize);
1838
1839 // Load RegExp data.
1840 __ bind(&success);
1841 __ mov(eax, Operand(esp, kJSRegExpOffset));
1842 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset));
1843 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset));
1844 // Calculate number of capture registers (number_of_captures + 1) * 2.
1845 STATIC_ASSERT(kSmiTag == 0);
1846 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001847 __ add(edx, Immediate(2)); // edx was a smi.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001848
1849 // edx: Number of capture registers
1850 // Load last_match_info which is still known to be a fast case JSArray.
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001851 // Check that the fourth object is a JSArray object.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001852 __ mov(eax, Operand(esp, kLastMatchInfoOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001853 __ JumpIfSmi(eax, &runtime);
1854 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
1855 __ j(not_equal, &runtime);
1856 // Check that the JSArray is in fast case.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001857 __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001858 __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset));
1859 __ cmp(eax, factory->fixed_array_map());
1860 __ j(not_equal, &runtime);
1861 // Check that the last match info has space for the capture registers and the
1862 // additional information.
1863 __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset));
1864 __ SmiUntag(eax);
1865 __ sub(eax, Immediate(RegExpImpl::kLastMatchOverhead));
1866 __ cmp(edx, eax);
1867 __ j(greater, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001868
1869 // ebx: last_match_info backing store (FixedArray)
1870 // edx: number of capture registers
1871 // Store the capture count.
1872 __ SmiTag(edx); // Number of capture registers to smi.
1873 __ mov(FieldOperand(ebx, RegExpImpl::kLastCaptureCountOffset), edx);
1874 __ SmiUntag(edx); // Number of capture registers back from smi.
1875 // Store last subject and last input.
1876 __ mov(eax, Operand(esp, kSubjectOffset));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001877 __ mov(ecx, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001878 __ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001879 __ RecordWriteField(ebx,
1880 RegExpImpl::kLastSubjectOffset,
1881 eax,
1882 edi,
1883 kDontSaveFPRegs);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001884 __ mov(eax, ecx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001885 __ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001886 __ RecordWriteField(ebx,
1887 RegExpImpl::kLastInputOffset,
1888 eax,
1889 edi,
1890 kDontSaveFPRegs);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001891
1892 // Get the static offsets vector filled by the native regexp code.
1893 ExternalReference address_of_static_offsets_vector =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001894 ExternalReference::address_of_static_offsets_vector(masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00001895 __ mov(ecx, Immediate(address_of_static_offsets_vector));
1896
1897 // ebx: last_match_info backing store (FixedArray)
1898 // ecx: offsets vector
1899 // edx: number of capture registers
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001900 Label next_capture, done;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001901 // Capture register counter starts from number of capture registers and
1902 // counts down until wraping after zero.
1903 __ bind(&next_capture);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001904 __ sub(edx, Immediate(1));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001905 __ j(negative, &done, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001906 // Read the value from the static offsets vector buffer.
1907 __ mov(edi, Operand(ecx, edx, times_int_size, 0));
1908 __ SmiTag(edi);
1909 // Store the smi value in the last match info.
1910 __ mov(FieldOperand(ebx,
1911 edx,
1912 times_pointer_size,
1913 RegExpImpl::kFirstCaptureOffset),
1914 edi);
1915 __ jmp(&next_capture);
1916 __ bind(&done);
1917
1918 // Return last match info.
1919 __ mov(eax, Operand(esp, kLastMatchInfoOffset));
1920 __ ret(4 * kPointerSize);
1921
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001922 // Do the runtime call to execute the regexp.
1923 __ bind(&runtime);
1924 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
1925
1926 // Deferred code for string handling.
1927 // (7) Not a long external string? If yes, go to (10).
1928 __ bind(&not_seq_nor_cons);
1929 // Compare flags are still set from (3).
1930 __ j(greater, &not_long_external, Label::kNear); // Go to (10).
1931
1932 // (8) External string. Short external strings have been ruled out.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001933 __ bind(&external_string);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001934 // Reload instance type.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001935 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
1936 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1937 if (FLAG_debug_code) {
1938 // Assert that we do not have a cons or slice (indirect strings) here.
1939 // Sequential strings have already been ruled out.
1940 __ test_b(ebx, kIsIndirectStringMask);
danno@chromium.org59400602013-08-13 17:09:37 +00001941 __ Assert(zero, kExternalStringExpectedButNotFound);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001942 }
1943 __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset));
1944 // Move the pointer so that offset-wise, it looks like a sequential string.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001945 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001946 __ sub(eax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
1947 STATIC_ASSERT(kTwoByteStringTag == 0);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001948 // (8a) Is the external string one byte? If yes, go to (6).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001949 __ test_b(ebx, kStringEncodingMask);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001950 __ j(not_zero, &seq_one_byte_string); // Goto (6).
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001951
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001952 // eax: sequential subject string (or look-alike, external string)
1953 // edx: original subject string
1954 // ecx: RegExp data (FixedArray)
1955 // (9) Two byte sequential. Load regexp code for one byte. Go to (E).
1956 __ bind(&seq_two_byte_string);
1957 // Load previous index and check range before edx is overwritten. We have
1958 // to use edx instead of eax here because it might have been only made to
1959 // look like a sequential string when it actually is an external string.
1960 __ mov(ebx, Operand(esp, kPreviousIndexOffset));
1961 __ JumpIfNotSmi(ebx, &runtime);
1962 __ cmp(ebx, FieldOperand(edx, String::kLengthOffset));
1963 __ j(above_equal, &runtime);
1964 __ mov(edx, FieldOperand(ecx, JSRegExp::kDataUC16CodeOffset));
1965 __ Set(ecx, Immediate(0)); // Type is two byte.
1966 __ jmp(&check_code); // Go to (E).
1967
1968 // (10) Not a string or a short external string? If yes, bail out to runtime.
1969 __ bind(&not_long_external);
1970 // Catch non-string subject or short external string.
1971 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0);
1972 __ test(ebx, Immediate(kIsNotStringMask | kShortExternalStringTag));
1973 __ j(not_zero, &runtime);
1974
1975 // (11) Sliced string. Replace subject with parent. Go to (5a).
1976 // Load offset into edi and replace subject string with parent.
1977 __ mov(edi, FieldOperand(eax, SlicedString::kOffsetOffset));
1978 __ mov(eax, FieldOperand(eax, SlicedString::kParentOffset));
1979 __ jmp(&check_underlying); // Go to (5a).
ricow@chromium.org65fae842010-08-25 15:26:24 +00001980#endif // V8_INTERPRETED_REGEXP
1981}
1982
1983
ricow@chromium.org65fae842010-08-25 15:26:24 +00001984static int NegativeComparisonResult(Condition cc) {
1985 ASSERT(cc != equal);
1986 ASSERT((cc == less) || (cc == less_equal)
1987 || (cc == greater) || (cc == greater_equal));
1988 return (cc == greater || cc == greater_equal) ? LESS : GREATER;
1989}
1990
ricow@chromium.org65fae842010-08-25 15:26:24 +00001991
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001992static void CheckInputType(MacroAssembler* masm,
1993 Register input,
1994 CompareIC::State expected,
1995 Label* fail) {
1996 Label ok;
1997 if (expected == CompareIC::SMI) {
1998 __ JumpIfNotSmi(input, fail);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001999 } else if (expected == CompareIC::NUMBER) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002000 __ JumpIfSmi(input, &ok);
2001 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
2002 Immediate(masm->isolate()->factory()->heap_number_map()));
2003 __ j(not_equal, fail);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002004 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002005 // We could be strict about internalized/non-internalized here, but as long as
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002006 // hydrogen doesn't care, the stub doesn't have to care either.
2007 __ bind(&ok);
2008}
2009
2010
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002011static void BranchIfNotInternalizedString(MacroAssembler* masm,
2012 Label* label,
2013 Register object,
2014 Register scratch) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002015 __ JumpIfSmi(object, label);
2016 __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset));
2017 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00002018 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
2019 __ test(scratch, Immediate(kIsNotStringMask | kIsNotInternalizedMask));
2020 __ j(not_zero, label);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002021}
2022
2023
2024void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
2025 Label check_unequal_objects;
2026 Condition cc = GetCondition();
2027
2028 Label miss;
2029 CheckInputType(masm, edx, left_, &miss);
2030 CheckInputType(masm, eax, right_, &miss);
2031
2032 // Compare two smis.
2033 Label non_smi, smi_done;
2034 __ mov(ecx, edx);
2035 __ or_(ecx, eax);
2036 __ JumpIfNotSmi(ecx, &non_smi, Label::kNear);
2037 __ sub(edx, eax); // Return on the result of the subtraction.
2038 __ j(no_overflow, &smi_done, Label::kNear);
2039 __ not_(edx); // Correct sign in case of overflow. edx is never 0 here.
2040 __ bind(&smi_done);
2041 __ mov(eax, edx);
2042 __ ret(0);
2043 __ bind(&non_smi);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002044
ricow@chromium.org65fae842010-08-25 15:26:24 +00002045 // NOTICE! This code is only reached after a smi-fast-case check, so
2046 // it is certain that at least one operand isn't a smi.
2047
2048 // Identical objects can be compared fast, but there are some tricky cases
2049 // for NaN and undefined.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002050 Label generic_heap_number_comparison;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002051 {
2052 Label not_identical;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002053 __ cmp(eax, edx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002054 __ j(not_equal, &not_identical);
2055
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002056 if (cc != equal) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002057 // Check for undefined. undefined OP undefined is false even though
2058 // undefined == undefined.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002059 Label check_for_nan;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002060 __ cmp(edx, masm->isolate()->factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002061 __ j(not_equal, &check_for_nan, Label::kNear);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002062 __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002063 __ ret(0);
2064 __ bind(&check_for_nan);
2065 }
2066
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002067 // Test for NaN. Compare heap numbers in a general way,
2068 // to hanlde NaNs correctly.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002069 __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
2070 Immediate(masm->isolate()->factory()->heap_number_map()));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002071 __ j(equal, &generic_heap_number_comparison, Label::kNear);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002072 if (cc != equal) {
2073 // Call runtime on identical JSObjects. Otherwise return equal.
2074 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
2075 __ j(above_equal, &not_identical);
2076 }
2077 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
2078 __ ret(0);
2079
ricow@chromium.org65fae842010-08-25 15:26:24 +00002080
2081 __ bind(&not_identical);
2082 }
2083
2084 // Strict equality can quickly decide whether objects are equal.
2085 // Non-strict object equality is slower, so it is handled later in the stub.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002086 if (cc == equal && strict()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002087 Label slow; // Fallthrough label.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002088 Label not_smis;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002089 // If we're doing a strict equality comparison, we don't have to do
2090 // type conversion, so we generate code to do fast comparison for objects
2091 // and oddballs. Non-smi numbers and strings still go through the usual
2092 // slow-case code.
2093 // If either is a Smi (we know that not both are), then they can only
2094 // be equal if the other is a HeapNumber. If so, use the slow case.
2095 STATIC_ASSERT(kSmiTag == 0);
2096 ASSERT_EQ(0, Smi::FromInt(0));
2097 __ mov(ecx, Immediate(kSmiTagMask));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002098 __ and_(ecx, eax);
2099 __ test(ecx, edx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002100 __ j(not_zero, &not_smis, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002101 // One operand is a smi.
2102
2103 // Check whether the non-smi is a heap number.
2104 STATIC_ASSERT(kSmiTagMask == 1);
2105 // ecx still holds eax & kSmiTag, which is either zero or one.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002106 __ sub(ecx, Immediate(0x01));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002107 __ mov(ebx, edx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002108 __ xor_(ebx, eax);
2109 __ and_(ebx, ecx); // ebx holds either 0 or eax ^ edx.
2110 __ xor_(ebx, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002111 // if eax was smi, ebx is now edx, else eax.
2112
2113 // Check if the non-smi operand is a heap number.
2114 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002115 Immediate(masm->isolate()->factory()->heap_number_map()));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002116 // If heap number, handle it in the slow case.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002117 __ j(equal, &slow, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002118 // Return non-equal (ebx is not zero)
2119 __ mov(eax, ebx);
2120 __ ret(0);
2121
2122 __ bind(&not_smis);
2123 // If either operand is a JSObject or an oddball value, then they are not
2124 // equal since their pointers are different
2125 // There is no test for undetectability in strict equality.
2126
2127 // Get the type of the first operand.
2128 // If the first object is a JS object, we have done pointer comparison.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002129 Label first_non_object;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002130 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
2131 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002132 __ j(below, &first_non_object, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002133
2134 // Return non-zero (eax is not zero)
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002135 Label return_not_equal;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002136 STATIC_ASSERT(kHeapObjectTag != 0);
2137 __ bind(&return_not_equal);
2138 __ ret(0);
2139
2140 __ bind(&first_non_object);
2141 // Check for oddballs: true, false, null, undefined.
2142 __ CmpInstanceType(ecx, ODDBALL_TYPE);
2143 __ j(equal, &return_not_equal);
2144
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002145 __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ecx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002146 __ j(above_equal, &return_not_equal);
2147
2148 // Check for oddballs: true, false, null, undefined.
2149 __ CmpInstanceType(ecx, ODDBALL_TYPE);
2150 __ j(equal, &return_not_equal);
2151
2152 // Fall through to the general case.
2153 __ bind(&slow);
2154 }
2155
2156 // Generate the number comparison code.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002157 Label non_number_comparison;
2158 Label unordered;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002159 __ bind(&generic_heap_number_comparison);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002160 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002161 CpuFeatureScope use_sse2(masm, SSE2);
2162 CpuFeatureScope use_cmov(masm, CMOV);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002163
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002164 FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison);
2165 __ ucomisd(xmm0, xmm1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002166
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002167 // Don't base result on EFLAGS when a NaN is involved.
2168 __ j(parity_even, &unordered, Label::kNear);
2169 // Return a result of -1, 0, or 1, based on EFLAGS.
2170 __ mov(eax, 0); // equal
2171 __ mov(ecx, Immediate(Smi::FromInt(1)));
2172 __ cmov(above, eax, ecx);
2173 __ mov(ecx, Immediate(Smi::FromInt(-1)));
2174 __ cmov(below, eax, ecx);
2175 __ ret(0);
2176 } else {
2177 FloatingPointHelper::CheckFloatOperands(
2178 masm, &non_number_comparison, ebx);
2179 FloatingPointHelper::LoadFloatOperand(masm, eax);
2180 FloatingPointHelper::LoadFloatOperand(masm, edx);
2181 __ FCmp();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002182
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002183 // Don't base result on EFLAGS when a NaN is involved.
2184 __ j(parity_even, &unordered, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002185
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002186 Label below_label, above_label;
2187 // Return a result of -1, 0, or 1, based on EFLAGS.
2188 __ j(below, &below_label, Label::kNear);
2189 __ j(above, &above_label, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002190
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002191 __ Set(eax, Immediate(0));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002192 __ ret(0);
2193
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002194 __ bind(&below_label);
2195 __ mov(eax, Immediate(Smi::FromInt(-1)));
2196 __ ret(0);
2197
2198 __ bind(&above_label);
2199 __ mov(eax, Immediate(Smi::FromInt(1)));
2200 __ ret(0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002201 }
2202
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002203 // If one of the numbers was NaN, then the result is always false.
2204 // The cc is never not-equal.
2205 __ bind(&unordered);
2206 ASSERT(cc != not_equal);
2207 if (cc == less || cc == less_equal) {
2208 __ mov(eax, Immediate(Smi::FromInt(1)));
2209 } else {
2210 __ mov(eax, Immediate(Smi::FromInt(-1)));
2211 }
2212 __ ret(0);
2213
2214 // The number comparison code did not provide a valid result.
2215 __ bind(&non_number_comparison);
2216
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002217 // Fast negative check for internalized-to-internalized equality.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002218 Label check_for_strings;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002219 if (cc == equal) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002220 BranchIfNotInternalizedString(masm, &check_for_strings, eax, ecx);
2221 BranchIfNotInternalizedString(masm, &check_for_strings, edx, ecx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002222
2223 // We've already checked for object identity, so if both operands
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002224 // are internalized they aren't equal. Register eax already holds a
ricow@chromium.org65fae842010-08-25 15:26:24 +00002225 // non-zero value, which indicates not equal, so just return.
2226 __ ret(0);
2227 }
2228
2229 __ bind(&check_for_strings);
2230
2231 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx,
2232 &check_unequal_objects);
2233
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002234 // Inline comparison of ASCII strings.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002235 if (cc == equal) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002236 StringCompareStub::GenerateFlatAsciiStringEquals(masm,
ricow@chromium.org65fae842010-08-25 15:26:24 +00002237 edx,
2238 eax,
2239 ecx,
lrn@chromium.org1c092762011-05-09 09:42:16 +00002240 ebx);
2241 } else {
2242 StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
2243 edx,
2244 eax,
2245 ecx,
2246 ebx,
2247 edi);
2248 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002249#ifdef DEBUG
danno@chromium.org59400602013-08-13 17:09:37 +00002250 __ Abort(kUnexpectedFallThroughFromStringComparison);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002251#endif
2252
2253 __ bind(&check_unequal_objects);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002254 if (cc == equal && !strict()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002255 // Non-strict equality. Objects are unequal if
2256 // they are both JSObjects and not undetectable,
2257 // and their pointers are different.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002258 Label not_both_objects;
2259 Label return_unequal;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002260 // At most one is a smi, so we can test for smi by adding the two.
2261 // A smi plus a heap object has the low bit set, a heap object plus
2262 // a heap object has the low bit clear.
2263 STATIC_ASSERT(kSmiTag == 0);
2264 STATIC_ASSERT(kSmiTagMask == 1);
2265 __ lea(ecx, Operand(eax, edx, times_1, 0));
2266 __ test(ecx, Immediate(kSmiTagMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002267 __ j(not_zero, &not_both_objects, Label::kNear);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002268 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002269 __ j(below, &not_both_objects, Label::kNear);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002270 __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ebx);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002271 __ j(below, &not_both_objects, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002272 // We do not bail out after this point. Both are JSObjects, and
2273 // they are equal if and only if both are undetectable.
2274 // The and of the undetectable flags is 1 if and only if they are equal.
2275 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
2276 1 << Map::kIsUndetectable);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002277 __ j(zero, &return_unequal, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002278 __ test_b(FieldOperand(ebx, Map::kBitFieldOffset),
2279 1 << Map::kIsUndetectable);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002280 __ j(zero, &return_unequal, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002281 // The objects are both undetectable, so they both compare as the value
2282 // undefined, and are equal.
2283 __ Set(eax, Immediate(EQUAL));
2284 __ bind(&return_unequal);
2285 // Return non-equal by returning the non-zero object pointer in eax,
2286 // or return equal if we fell through to here.
2287 __ ret(0); // rax, rdx were pushed
2288 __ bind(&not_both_objects);
2289 }
2290
2291 // Push arguments below the return address.
2292 __ pop(ecx);
2293 __ push(edx);
2294 __ push(eax);
2295
2296 // Figure out which native to call and setup the arguments.
2297 Builtins::JavaScript builtin;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002298 if (cc == equal) {
2299 builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002300 } else {
2301 builtin = Builtins::COMPARE;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002302 __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002303 }
2304
2305 // Restore return address on the stack.
2306 __ push(ecx);
2307
2308 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
2309 // tagged as a small integer.
2310 __ InvokeBuiltin(builtin, JUMP_FUNCTION);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002311
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002312 __ bind(&miss);
2313 GenerateMiss(masm);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002314}
2315
2316
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002317static void GenerateRecordCallTarget(MacroAssembler* masm) {
2318 // Cache the called function in a global property cell. Cache states
2319 // are uninitialized, monomorphic (indicated by a JSFunction), and
2320 // megamorphic.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002321 // eax : number of arguments to the construct function
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002322 // ebx : cache cell for call target
2323 // edi : the function to call
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002324 Isolate* isolate = masm->isolate();
2325 Label initialize, done, miss, megamorphic, not_array_function;
2326
2327 // Load the cache state into ecx.
danno@chromium.org41728482013-06-12 22:31:22 +00002328 __ mov(ecx, FieldOperand(ebx, Cell::kValueOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002329
2330 // A monomorphic cache hit or an already megamorphic state: invoke the
2331 // function without changing the state.
2332 __ cmp(ecx, edi);
2333 __ j(equal, &done);
2334 __ cmp(ecx, Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
2335 __ j(equal, &done);
2336
danno@chromium.orgbee51992013-07-10 14:57:15 +00002337 // If we came here, we need to see if we are the array function.
2338 // If we didn't have a matching function, and we didn't find the megamorph
2339 // sentinel, then we have in the cell either some other function or an
2340 // AllocationSite. Do a map check on the object in ecx.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002341 Handle<Map> allocation_site_map =
2342 masm->isolate()->factory()->allocation_site_map();
danno@chromium.orgbee51992013-07-10 14:57:15 +00002343 __ cmp(FieldOperand(ecx, 0), Immediate(allocation_site_map));
2344 __ j(not_equal, &miss);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002345
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002346 // Load the global or builtins object from the current context
2347 __ LoadGlobalContext(ecx);
2348 // Make sure the function is the Array() function
2349 __ cmp(edi, Operand(ecx,
2350 Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
2351 __ j(not_equal, &megamorphic);
2352 __ jmp(&done);
2353
2354 __ bind(&miss);
2355
2356 // A monomorphic miss (i.e, here the cache is not uninitialized) goes
2357 // megamorphic.
2358 __ cmp(ecx, Immediate(TypeFeedbackCells::UninitializedSentinel(isolate)));
2359 __ j(equal, &initialize);
2360 // MegamorphicSentinel is an immortal immovable object (undefined) so no
2361 // write-barrier is needed.
2362 __ bind(&megamorphic);
danno@chromium.org41728482013-06-12 22:31:22 +00002363 __ mov(FieldOperand(ebx, Cell::kValueOffset),
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002364 Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
2365 __ jmp(&done, Label::kNear);
2366
2367 // An uninitialized cache is patched with the function or sentinel to
2368 // indicate the ElementsKind if function is the Array constructor.
2369 __ bind(&initialize);
2370 __ LoadGlobalContext(ecx);
2371 // Make sure the function is the Array() function
2372 __ cmp(edi, Operand(ecx,
2373 Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
2374 __ j(not_equal, &not_array_function);
2375
danno@chromium.orgbee51992013-07-10 14:57:15 +00002376 // The target function is the Array constructor,
2377 // Create an AllocationSite if we don't already have it, store it in the cell
2378 {
2379 FrameScope scope(masm, StackFrame::INTERNAL);
2380
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002381 // Arguments register must be smi-tagged to call out.
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002382 __ SmiTag(eax);
danno@chromium.orgbee51992013-07-10 14:57:15 +00002383 __ push(eax);
2384 __ push(edi);
2385 __ push(ebx);
2386
2387 CreateAllocationSiteStub create_stub;
2388 __ CallStub(&create_stub);
2389
2390 __ pop(ebx);
2391 __ pop(edi);
2392 __ pop(eax);
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002393 __ SmiUntag(eax);
danno@chromium.orgbee51992013-07-10 14:57:15 +00002394 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002395 __ jmp(&done);
2396
2397 __ bind(&not_array_function);
danno@chromium.org41728482013-06-12 22:31:22 +00002398 __ mov(FieldOperand(ebx, Cell::kValueOffset), edi);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002399 // No need for a write barrier here - cells are rescanned.
2400
2401 __ bind(&done);
2402}
2403
2404
ricow@chromium.org65fae842010-08-25 15:26:24 +00002405void CallFunctionStub::Generate(MacroAssembler* masm) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002406 // ebx : cache cell for call target
danno@chromium.orgc612e022011-11-10 11:38:15 +00002407 // edi : the function to call
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002408 Isolate* isolate = masm->isolate();
lrn@chromium.org34e60782011-09-15 07:25:40 +00002409 Label slow, non_function;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002410
rossberg@chromium.org9ed27462014-01-07 14:16:41 +00002411 // Check that the function really is a JavaScript function.
2412 __ JumpIfSmi(edi, &non_function);
2413
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002414 // Goto slow case if we do not have a function.
2415 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2416 __ j(not_equal, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002417
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002418 if (RecordCallTarget()) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002419 GenerateRecordCallTarget(masm);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002420 }
2421
ricow@chromium.org65fae842010-08-25 15:26:24 +00002422 // Fast-case: Just invoke the function.
2423 ParameterCount actual(argc_);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002424
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00002425 __ InvokeFunction(edi, actual, JUMP_FUNCTION, NullCallWrapper());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002426
2427 // Slow-case: Non-function called.
2428 __ bind(&slow);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002429 if (RecordCallTarget()) {
2430 // If there is a call target cache, mark it megamorphic in the
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002431 // non-function case. MegamorphicSentinel is an immortal immovable
2432 // object (undefined) so no write barrier is needed.
danno@chromium.org41728482013-06-12 22:31:22 +00002433 __ mov(FieldOperand(ebx, Cell::kValueOffset),
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002434 Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002435 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00002436 // Check for function proxy.
2437 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
2438 __ j(not_equal, &non_function);
2439 __ pop(ecx);
2440 __ push(edi); // put proxy as additional argument under return address
2441 __ push(ecx);
2442 __ Set(eax, Immediate(argc_ + 1));
2443 __ Set(ebx, Immediate(0));
lrn@chromium.org34e60782011-09-15 07:25:40 +00002444 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
2445 {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002446 Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline();
lrn@chromium.org34e60782011-09-15 07:25:40 +00002447 __ jmp(adaptor, RelocInfo::CODE_TARGET);
2448 }
2449
ricow@chromium.org65fae842010-08-25 15:26:24 +00002450 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
2451 // of the original receiver from the call site).
lrn@chromium.org34e60782011-09-15 07:25:40 +00002452 __ bind(&non_function);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002453 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi);
2454 __ Set(eax, Immediate(argc_));
2455 __ Set(ebx, Immediate(0));
2456 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002457 Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002458 __ jmp(adaptor, RelocInfo::CODE_TARGET);
2459}
2460
2461
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002462void CallConstructStub::Generate(MacroAssembler* masm) {
2463 // eax : number of arguments
2464 // ebx : cache cell for call target
2465 // edi : constructor function
2466 Label slow, non_function_call;
2467
2468 // Check that function is not a smi.
2469 __ JumpIfSmi(edi, &non_function_call);
2470 // Check that function is a JSFunction.
2471 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2472 __ j(not_equal, &slow);
2473
2474 if (RecordCallTarget()) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002475 GenerateRecordCallTarget(masm);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002476 }
2477
2478 // Jump to the function-specific construct stub.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002479 Register jmp_reg = ecx;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002480 __ mov(jmp_reg, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2481 __ mov(jmp_reg, FieldOperand(jmp_reg,
2482 SharedFunctionInfo::kConstructStubOffset));
2483 __ lea(jmp_reg, FieldOperand(jmp_reg, Code::kHeaderSize));
2484 __ jmp(jmp_reg);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002485
2486 // edi: called object
2487 // eax: number of arguments
2488 // ecx: object map
2489 Label do_call;
2490 __ bind(&slow);
2491 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
2492 __ j(not_equal, &non_function_call);
2493 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
2494 __ jmp(&do_call);
2495
2496 __ bind(&non_function_call);
2497 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
2498 __ bind(&do_call);
2499 // Set expected number of arguments to zero (not changing eax).
2500 __ Set(ebx, Immediate(0));
2501 Handle<Code> arguments_adaptor =
2502 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002503 __ jmp(arguments_adaptor, RelocInfo::CODE_TARGET);
2504}
2505
2506
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002507bool CEntryStub::NeedsImmovableCode() {
2508 return false;
2509}
2510
2511
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002512void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
2513 CEntryStub::GenerateAheadOfTime(isolate);
2514 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002515 StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002516 // It is important that the store buffer overflow stubs are generated first.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002517 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
danno@chromium.orgbee51992013-07-10 14:57:15 +00002518 CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
mvstanton@chromium.org182d2db2013-10-10 11:03:05 +00002519 if (Serializer::enabled()) {
2520 PlatformFeatureScope sse2(SSE2);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00002521 BinaryOpICStub::GenerateAheadOfTime(isolate);
ulan@chromium.org0f13e742014-01-03 15:51:11 +00002522 BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
mvstanton@chromium.org182d2db2013-10-10 11:03:05 +00002523 } else {
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00002524 BinaryOpICStub::GenerateAheadOfTime(isolate);
ulan@chromium.org0f13e742014-01-03 15:51:11 +00002525 BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
mvstanton@chromium.org182d2db2013-10-10 11:03:05 +00002526 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002527}
2528
2529
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002530void CodeStub::GenerateFPStubs(Isolate* isolate) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002531 if (CpuFeatures::IsSupported(SSE2)) {
2532 CEntryStub save_doubles(1, kSaveFPRegs);
2533 // Stubs might already be in the snapshot, detect that and don't regenerate,
2534 // which would lead to code stub initialization state being messed up.
2535 Code* save_doubles_code;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002536 if (!save_doubles.FindCodeInCache(&save_doubles_code, isolate)) {
2537 save_doubles_code = *(save_doubles.GetCode(isolate));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002538 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002539 isolate->set_fp_stubs_generated(true);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002540 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002541}
2542
2543
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002544void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002545 CEntryStub stub(1, kDontSaveFPRegs);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002546 stub.GetCode(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002547}
2548
2549
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002550static void JumpIfOOM(MacroAssembler* masm,
2551 Register value,
2552 Register scratch,
2553 Label* oom_label) {
2554 __ mov(scratch, value);
2555 STATIC_ASSERT(Failure::OUT_OF_MEMORY_EXCEPTION == 3);
2556 STATIC_ASSERT(kFailureTag == 3);
2557 __ and_(scratch, 0xf);
2558 __ cmp(scratch, 0xf);
2559 __ j(equal, oom_label);
2560}
2561
2562
ricow@chromium.org65fae842010-08-25 15:26:24 +00002563void CEntryStub::GenerateCore(MacroAssembler* masm,
2564 Label* throw_normal_exception,
2565 Label* throw_termination_exception,
2566 Label* throw_out_of_memory_exception,
2567 bool do_gc,
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002568 bool always_allocate_scope) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002569 // eax: result parameter for PerformGC, if any
2570 // ebx: pointer to C function (C callee-saved)
2571 // ebp: frame pointer (restored after C call)
2572 // esp: stack pointer (restored after C call)
2573 // edi: number of arguments including receiver (C callee-saved)
2574 // esi: pointer to the first argument (C callee-saved)
2575
2576 // Result returned in eax, or eax+edx if result_size_ is 2.
2577
2578 // Check stack alignment.
2579 if (FLAG_debug_code) {
2580 __ CheckStackAlignment();
2581 }
2582
2583 if (do_gc) {
2584 // Pass failure code returned from last attempt as first argument to
2585 // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the
2586 // stack alignment is known to be correct. This function takes one argument
2587 // which is passed on the stack, and we know that the stack has been
2588 // prepared to pass at least one argument.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002589 __ mov(Operand(esp, 1 * kPointerSize),
2590 Immediate(ExternalReference::isolate_address(masm->isolate())));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002591 __ mov(Operand(esp, 0 * kPointerSize), eax); // Result.
2592 __ call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY);
2593 }
2594
2595 ExternalReference scope_depth =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002596 ExternalReference::heap_always_allocate_scope_depth(masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002597 if (always_allocate_scope) {
2598 __ inc(Operand::StaticVariable(scope_depth));
2599 }
2600
2601 // Call C function.
2602 __ mov(Operand(esp, 0 * kPointerSize), edi); // argc.
2603 __ mov(Operand(esp, 1 * kPointerSize), esi); // argv.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002604 __ mov(Operand(esp, 2 * kPointerSize),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002605 Immediate(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002606 __ call(ebx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002607 // Result is in eax or edx:eax - do not destroy these registers!
2608
2609 if (always_allocate_scope) {
2610 __ dec(Operand::StaticVariable(scope_depth));
2611 }
2612
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002613 // Runtime functions should not return 'the hole'. Allowing it to escape may
2614 // lead to crashes in the IC code later.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002615 if (FLAG_debug_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002616 Label okay;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002617 __ cmp(eax, masm->isolate()->factory()->the_hole_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002618 __ j(not_equal, &okay, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002619 __ int3();
2620 __ bind(&okay);
2621 }
2622
2623 // Check for failure result.
2624 Label failure_returned;
2625 STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
2626 __ lea(ecx, Operand(eax, 1));
2627 // Lower 2 bits of ecx are 0 iff eax has failure tag.
2628 __ test(ecx, Immediate(kFailureTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002629 __ j(zero, &failure_returned);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002630
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002631 ExternalReference pending_exception_address(
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002632 Isolate::kPendingExceptionAddress, masm->isolate());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002633
2634 // Check that there is no pending exception, otherwise we
2635 // should have returned some failure value.
2636 if (FLAG_debug_code) {
2637 __ push(edx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002638 __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002639 Label okay;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002640 __ cmp(edx, Operand::StaticVariable(pending_exception_address));
2641 // Cannot use check here as it attempts to generate call into runtime.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002642 __ j(equal, &okay, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002643 __ int3();
2644 __ bind(&okay);
2645 __ pop(edx);
2646 }
2647
ricow@chromium.org65fae842010-08-25 15:26:24 +00002648 // Exit the JavaScript to C++ exit frame.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002649 __ LeaveExitFrame(save_doubles_ == kSaveFPRegs);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002650 __ ret(0);
2651
2652 // Handling of failure.
2653 __ bind(&failure_returned);
2654
2655 Label retry;
2656 // If the returned exception is RETRY_AFTER_GC continue at retry label
2657 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0);
2658 __ test(eax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002659 __ j(zero, &retry, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002660
2661 // Special handling of out of memory exceptions.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002662 JumpIfOOM(masm, eax, ecx, throw_out_of_memory_exception);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002663
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002664 // Retrieve the pending exception.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002665 __ mov(eax, Operand::StaticVariable(pending_exception_address));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002666
2667 // See if we just retrieved an OOM exception.
2668 JumpIfOOM(masm, eax, ecx, throw_out_of_memory_exception);
2669
2670 // Clear the pending exception.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002671 __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002672 __ mov(Operand::StaticVariable(pending_exception_address), edx);
2673
2674 // Special handling of termination exceptions which are uncatchable
2675 // by javascript code.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002676 __ cmp(eax, masm->isolate()->factory()->termination_exception());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002677 __ j(equal, throw_termination_exception);
2678
2679 // Handle normal exception.
2680 __ jmp(throw_normal_exception);
2681
2682 // Retry.
2683 __ bind(&retry);
2684}
2685
2686
ricow@chromium.org65fae842010-08-25 15:26:24 +00002687void CEntryStub::Generate(MacroAssembler* masm) {
2688 // eax: number of arguments including receiver
2689 // ebx: pointer to C function (C callee-saved)
2690 // ebp: frame pointer (restored after C call)
2691 // esp: stack pointer (restored after C call)
2692 // esi: current context (C callee-saved)
2693 // edi: JS function of the caller (C callee-saved)
2694
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002695 ProfileEntryHookStub::MaybeCallEntryHook(masm);
2696
ricow@chromium.org65fae842010-08-25 15:26:24 +00002697 // NOTE: Invocations of builtins may return failure objects instead
2698 // of a proper result. The builtin entry handles this by performing
2699 // a garbage collection and retrying the builtin (twice).
2700
2701 // Enter the exit frame that transitions from JavaScript to C++.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002702 __ EnterExitFrame(save_doubles_ == kSaveFPRegs);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002703
2704 // eax: result parameter for PerformGC, if any (setup below)
2705 // ebx: pointer to builtin function (C callee-saved)
2706 // ebp: frame pointer (restored after C call)
2707 // esp: stack pointer (restored after C call)
2708 // edi: number of arguments including receiver (C callee-saved)
2709 // esi: argv pointer (C callee-saved)
2710
2711 Label throw_normal_exception;
2712 Label throw_termination_exception;
2713 Label throw_out_of_memory_exception;
2714
2715 // Call into the runtime system.
2716 GenerateCore(masm,
2717 &throw_normal_exception,
2718 &throw_termination_exception,
2719 &throw_out_of_memory_exception,
2720 false,
2721 false);
2722
2723 // Do space-specific GC and retry runtime call.
2724 GenerateCore(masm,
2725 &throw_normal_exception,
2726 &throw_termination_exception,
2727 &throw_out_of_memory_exception,
2728 true,
2729 false);
2730
2731 // Do full GC and retry runtime call one final time.
2732 Failure* failure = Failure::InternalError();
2733 __ mov(eax, Immediate(reinterpret_cast<int32_t>(failure)));
2734 GenerateCore(masm,
2735 &throw_normal_exception,
2736 &throw_termination_exception,
2737 &throw_out_of_memory_exception,
2738 true,
2739 true);
2740
2741 __ bind(&throw_out_of_memory_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002742 // Set external caught exception to false.
2743 Isolate* isolate = masm->isolate();
2744 ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress,
2745 isolate);
2746 __ mov(Operand::StaticVariable(external_caught), Immediate(false));
2747
2748 // Set pending exception and eax to out of memory exception.
2749 ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
2750 isolate);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002751 Label already_have_failure;
2752 JumpIfOOM(masm, eax, ecx, &already_have_failure);
2753 __ mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException(0x1)));
2754 __ bind(&already_have_failure);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002755 __ mov(Operand::StaticVariable(pending_exception), eax);
2756 // Fall through to the next label.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002757
2758 __ bind(&throw_termination_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002759 __ ThrowUncatchable(eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002760
2761 __ bind(&throw_normal_exception);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002762 __ Throw(eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002763}
2764
2765
2766void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002767 Label invoke, handler_entry, exit;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002768 Label not_outermost_js, not_outermost_js_2;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002769
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002770 ProfileEntryHookStub::MaybeCallEntryHook(masm);
2771
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002772 // Set up frame.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002773 __ push(ebp);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002774 __ mov(ebp, esp);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002775
2776 // Push marker in two places.
2777 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
2778 __ push(Immediate(Smi::FromInt(marker))); // context slot
2779 __ push(Immediate(Smi::FromInt(marker))); // function slot
2780 // Save callee-saved registers (C calling conventions).
2781 __ push(edi);
2782 __ push(esi);
2783 __ push(ebx);
2784
2785 // Save copies of the top frame descriptor on the stack.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002786 ExternalReference c_entry_fp(Isolate::kCEntryFPAddress, masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002787 __ push(Operand::StaticVariable(c_entry_fp));
2788
ricow@chromium.org65fae842010-08-25 15:26:24 +00002789 // If this is the outermost JS call, set js_entry_sp value.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002790 ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002791 masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002792 __ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002793 __ j(not_equal, &not_outermost_js, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002794 __ mov(Operand::StaticVariable(js_entry_sp), ebp);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002795 __ push(Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
danno@chromium.org2c26cb12012-05-03 09:06:43 +00002796 __ jmp(&invoke, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002797 __ bind(&not_outermost_js);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002798 __ push(Immediate(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002799
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002800 // Jump to a faked try block that does the invoke, with a faked catch
2801 // block that sets the pending exception.
2802 __ jmp(&invoke);
2803 __ bind(&handler_entry);
2804 handler_offset_ = handler_entry.pos();
2805 // Caught exception: Store result (exception) in the pending exception
2806 // field in the JSEnv and return a failure sentinel.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002807 ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002808 masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002809 __ mov(Operand::StaticVariable(pending_exception), eax);
2810 __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception()));
2811 __ jmp(&exit);
2812
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002813 // Invoke: Link this frame into the handler chain. There's only one
2814 // handler block in this code object, so its index is 0.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002815 __ bind(&invoke);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002816 __ PushTryHandler(StackHandler::JS_ENTRY, 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002817
2818 // Clear any pending exceptions.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002819 __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002820 __ mov(Operand::StaticVariable(pending_exception), edx);
2821
2822 // Fake a receiver (NULL).
2823 __ push(Immediate(0)); // receiver
2824
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002825 // Invoke the function by calling through JS entry trampoline builtin and
2826 // pop the faked function when we return. Notice that we cannot store a
2827 // reference to the trampoline code directly in this stub, because the
2828 // builtin stubs may not have been generated yet.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002829 if (is_construct) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002830 ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline,
2831 masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002832 __ mov(edx, Immediate(construct_entry));
2833 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002834 ExternalReference entry(Builtins::kJSEntryTrampoline,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002835 masm->isolate());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002836 __ mov(edx, Immediate(entry));
2837 }
2838 __ mov(edx, Operand(edx, 0)); // deref address
2839 __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002840 __ call(edx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002841
2842 // Unlink this frame from the handler chain.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002843 __ PopTryHandler();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002844
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002845 __ bind(&exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002846 // Check if the current stack frame is marked as the outermost JS frame.
2847 __ pop(ebx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002848 __ cmp(ebx, Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002849 __ j(not_equal, &not_outermost_js_2);
2850 __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0));
2851 __ bind(&not_outermost_js_2);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002852
2853 // Restore the top frame descriptor from the stack.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002854 __ pop(Operand::StaticVariable(ExternalReference(
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002855 Isolate::kCEntryFPAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002856 masm->isolate())));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002857
2858 // Restore callee-saved registers (C calling conventions).
2859 __ pop(ebx);
2860 __ pop(esi);
2861 __ pop(edi);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002862 __ add(esp, Immediate(2 * kPointerSize)); // remove markers
ricow@chromium.org65fae842010-08-25 15:26:24 +00002863
2864 // Restore frame pointer and return.
2865 __ pop(ebp);
2866 __ ret(0);
2867}
2868
2869
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002870// Generate stub code for instanceof.
2871// This code can patch a call site inlined cache of the instance of check,
2872// which looks like this.
2873//
2874// 81 ff XX XX XX XX cmp edi, <the hole, patched to a map>
2875// 75 0a jne <some near label>
2876// b8 XX XX XX XX mov eax, <the hole, patched to either true or false>
2877//
2878// If call site patching is requested the stack will have the delta from the
2879// return address to the cmp instruction just below the return address. This
2880// also means that call site patching can only take place with arguments in
2881// registers. TOS looks like this when call site patching is requested
2882//
2883// esp[0] : return address
2884// esp[4] : delta from return address to cmp instruction
2885//
ricow@chromium.org65fae842010-08-25 15:26:24 +00002886void InstanceofStub::Generate(MacroAssembler* masm) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002887 // Call site inlining and patching implies arguments in registers.
2888 ASSERT(HasArgsInRegisters() || !HasCallSiteInlineCheck());
2889
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002890 // Fixed register usage throughout the stub.
2891 Register object = eax; // Object (lhs).
2892 Register map = ebx; // Map of the object.
2893 Register function = edx; // Function (rhs).
2894 Register prototype = edi; // Prototype of the function.
2895 Register scratch = ecx;
2896
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002897 // Constants describing the call site code to patch.
2898 static const int kDeltaToCmpImmediate = 2;
2899 static const int kDeltaToMov = 8;
2900 static const int kDeltaToMovImmediate = 9;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002901 static const int8_t kCmpEdiOperandByte1 = BitCast<int8_t, uint8_t>(0x3b);
2902 static const int8_t kCmpEdiOperandByte2 = BitCast<int8_t, uint8_t>(0x3d);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002903 static const int8_t kMovEaxImmediateByte = BitCast<int8_t, uint8_t>(0xb8);
2904
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002905 ASSERT_EQ(object.code(), InstanceofStub::left().code());
2906 ASSERT_EQ(function.code(), InstanceofStub::right().code());
2907
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002908 // Get the object and function - they are always both needed.
2909 Label slow, not_js_object;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002910 if (!HasArgsInRegisters()) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002911 __ mov(object, Operand(esp, 2 * kPointerSize));
2912 __ mov(function, Operand(esp, 1 * kPointerSize));
2913 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002914
2915 // Check that the left hand is a JS object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002916 __ JumpIfSmi(object, &not_js_object);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002917 __ IsObjectJSObjectType(object, map, scratch, &not_js_object);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002918
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002919 // If there is a call site cache don't look in the global cache, but do the
2920 // real lookup and update the call site cache.
2921 if (!HasCallSiteInlineCheck()) {
2922 // Look up the function and the map in the instanceof cache.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002923 Label miss;
danno@chromium.org59400602013-08-13 17:09:37 +00002924 __ CompareRoot(function, scratch, Heap::kInstanceofCacheFunctionRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002925 __ j(not_equal, &miss, Label::kNear);
danno@chromium.org59400602013-08-13 17:09:37 +00002926 __ CompareRoot(map, scratch, Heap::kInstanceofCacheMapRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002927 __ j(not_equal, &miss, Label::kNear);
danno@chromium.org59400602013-08-13 17:09:37 +00002928 __ LoadRoot(eax, Heap::kInstanceofCacheAnswerRootIndex);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002929 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
2930 __ bind(&miss);
2931 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002932
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002933 // Get the prototype of the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002934 __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002935
2936 // Check that the function prototype is a JS object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002937 __ JumpIfSmi(prototype, &slow);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002938 __ IsObjectJSObjectType(prototype, scratch, scratch, &slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002939
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002940 // Update the global instanceof or call site inlined cache with the current
2941 // map and function. The cached answer will be set when it is known below.
2942 if (!HasCallSiteInlineCheck()) {
danno@chromium.org59400602013-08-13 17:09:37 +00002943 __ StoreRoot(map, scratch, Heap::kInstanceofCacheMapRootIndex);
2944 __ StoreRoot(function, scratch, Heap::kInstanceofCacheFunctionRootIndex);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002945 } else {
2946 // The constants for the code patching are based on no push instructions
2947 // at the call site.
2948 ASSERT(HasArgsInRegisters());
2949 // Get return address and delta to inlined map check.
2950 __ mov(scratch, Operand(esp, 0 * kPointerSize));
2951 __ sub(scratch, Operand(esp, 1 * kPointerSize));
2952 if (FLAG_debug_code) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002953 __ cmpb(Operand(scratch, 0), kCmpEdiOperandByte1);
danno@chromium.org59400602013-08-13 17:09:37 +00002954 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheCmp1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002955 __ cmpb(Operand(scratch, 1), kCmpEdiOperandByte2);
danno@chromium.org59400602013-08-13 17:09:37 +00002956 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheCmp2);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002957 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002958 __ mov(scratch, Operand(scratch, kDeltaToCmpImmediate));
2959 __ mov(Operand(scratch, 0), map);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002960 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002961
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002962 // Loop through the prototype chain of the object looking for the function
2963 // prototype.
2964 __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002965 Label loop, is_instance, is_not_instance;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002966 __ bind(&loop);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002967 __ cmp(scratch, prototype);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002968 __ j(equal, &is_instance, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002969 Factory* factory = masm->isolate()->factory();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002970 __ cmp(scratch, Immediate(factory->null_value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002971 __ j(equal, &is_not_instance, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002972 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
2973 __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002974 __ jmp(&loop);
2975
2976 __ bind(&is_instance);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002977 if (!HasCallSiteInlineCheck()) {
danno@chromium.org59400602013-08-13 17:09:37 +00002978 __ mov(eax, Immediate(0));
2979 __ StoreRoot(eax, scratch, Heap::kInstanceofCacheAnswerRootIndex);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002980 } else {
2981 // Get return address and delta to inlined map check.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002982 __ mov(eax, factory->true_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002983 __ mov(scratch, Operand(esp, 0 * kPointerSize));
2984 __ sub(scratch, Operand(esp, 1 * kPointerSize));
2985 if (FLAG_debug_code) {
2986 __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte);
danno@chromium.org59400602013-08-13 17:09:37 +00002987 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002988 }
2989 __ mov(Operand(scratch, kDeltaToMovImmediate), eax);
2990 if (!ReturnTrueFalseObject()) {
2991 __ Set(eax, Immediate(0));
2992 }
2993 }
2994 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002995
2996 __ bind(&is_not_instance);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002997 if (!HasCallSiteInlineCheck()) {
danno@chromium.org59400602013-08-13 17:09:37 +00002998 __ mov(eax, Immediate(Smi::FromInt(1)));
2999 __ StoreRoot(eax, scratch, Heap::kInstanceofCacheAnswerRootIndex);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003000 } else {
3001 // Get return address and delta to inlined map check.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003002 __ mov(eax, factory->false_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003003 __ mov(scratch, Operand(esp, 0 * kPointerSize));
3004 __ sub(scratch, Operand(esp, 1 * kPointerSize));
3005 if (FLAG_debug_code) {
3006 __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte);
danno@chromium.org59400602013-08-13 17:09:37 +00003007 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003008 }
3009 __ mov(Operand(scratch, kDeltaToMovImmediate), eax);
3010 if (!ReturnTrueFalseObject()) {
3011 __ Set(eax, Immediate(Smi::FromInt(1)));
3012 }
3013 }
3014 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003015
3016 Label object_not_null, object_not_null_or_smi;
3017 __ bind(&not_js_object);
3018 // Before null, smi and string value checks, check that the rhs is a function
3019 // as for a non-function rhs an exception needs to be thrown.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003020 __ JumpIfSmi(function, &slow, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003021 __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003022 __ j(not_equal, &slow, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003023
3024 // Null is not instance of anything.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003025 __ cmp(object, factory->null_value());
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003026 __ j(not_equal, &object_not_null, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003027 __ Set(eax, Immediate(Smi::FromInt(1)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003028 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003029
3030 __ bind(&object_not_null);
3031 // Smi values is not instance of anything.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003032 __ JumpIfNotSmi(object, &object_not_null_or_smi, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003033 __ Set(eax, Immediate(Smi::FromInt(1)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003034 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003035
3036 __ bind(&object_not_null_or_smi);
3037 // String values is not instance of anything.
3038 Condition is_string = masm->IsObjectStringType(object, scratch, scratch);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003039 __ j(NegateCondition(is_string), &slow, Label::kNear);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003040 __ Set(eax, Immediate(Smi::FromInt(1)));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003041 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003042
3043 // Slow-case: Go through the JavaScript implementation.
3044 __ bind(&slow);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003045 if (!ReturnTrueFalseObject()) {
3046 // Tail call the builtin which returns 0 or 1.
3047 if (HasArgsInRegisters()) {
3048 // Push arguments below return address.
3049 __ pop(scratch);
3050 __ push(object);
3051 __ push(function);
3052 __ push(scratch);
3053 }
3054 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
3055 } else {
3056 // Call the builtin and convert 0/1 to true/false.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003057 {
3058 FrameScope scope(masm, StackFrame::INTERNAL);
3059 __ push(object);
3060 __ push(function);
3061 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
3062 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003063 Label true_value, done;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003064 __ test(eax, eax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003065 __ j(zero, &true_value, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003066 __ mov(eax, factory->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003067 __ jmp(&done, Label::kNear);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003068 __ bind(&true_value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003069 __ mov(eax, factory->true_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003070 __ bind(&done);
3071 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003072 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003073}
3074
3075
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003076Register InstanceofStub::left() { return eax; }
3077
3078
3079Register InstanceofStub::right() { return edx; }
3080
3081
ricow@chromium.org65fae842010-08-25 15:26:24 +00003082// -------------------------------------------------------------------------
3083// StringCharCodeAtGenerator
3084
3085void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003086 // If the receiver is a smi trigger the non-string case.
3087 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003088 __ JumpIfSmi(object_, receiver_not_string_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003089
3090 // Fetch the instance type of the receiver into result register.
3091 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
3092 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
3093 // If the receiver is not a string trigger the non-string case.
3094 __ test(result_, Immediate(kIsNotStringMask));
3095 __ j(not_zero, receiver_not_string_);
3096
3097 // If the index is non-smi trigger the non-smi case.
3098 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003099 __ JumpIfNotSmi(index_, &index_not_smi_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003100 __ bind(&got_smi_index_);
3101
3102 // Check for index out of range.
danno@chromium.orgc612e022011-11-10 11:38:15 +00003103 __ cmp(index_, FieldOperand(object_, String::kLengthOffset));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003104 __ j(above_equal, index_out_of_range_);
3105
danno@chromium.orgc612e022011-11-10 11:38:15 +00003106 __ SmiUntag(index_);
erikcorry0ad885c2011-11-21 13:51:57 +00003107
3108 Factory* factory = masm->isolate()->factory();
3109 StringCharLoadGenerator::Generate(
3110 masm, factory, object_, index_, result_, &call_runtime_);
3111
ricow@chromium.org65fae842010-08-25 15:26:24 +00003112 __ SmiTag(result_);
3113 __ bind(&exit_);
3114}
3115
3116
3117void StringCharCodeAtGenerator::GenerateSlow(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003118 MacroAssembler* masm,
3119 const RuntimeCallHelper& call_helper) {
danno@chromium.org59400602013-08-13 17:09:37 +00003120 __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003121
3122 // Index is not a smi.
3123 __ bind(&index_not_smi_);
3124 // If index is a heap number, try converting it to an integer.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003125 __ CheckMap(index_,
3126 masm->isolate()->factory()->heap_number_map(),
3127 index_not_number_,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003128 DONT_DO_SMI_CHECK);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003129 call_helper.BeforeCall(masm);
3130 __ push(object_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003131 __ push(index_); // Consumed by runtime conversion function.
3132 if (index_flags_ == STRING_INDEX_IS_NUMBER) {
3133 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
3134 } else {
3135 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
3136 // NumberToSmi discards numbers that are not exact integers.
3137 __ CallRuntime(Runtime::kNumberToSmi, 1);
3138 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00003139 if (!index_.is(eax)) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003140 // Save the conversion result before the pop instructions below
3141 // have a chance to overwrite it.
danno@chromium.orgc612e022011-11-10 11:38:15 +00003142 __ mov(index_, eax);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003143 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003144 __ pop(object_);
3145 // Reload the instance type.
3146 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
3147 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
3148 call_helper.AfterCall(masm);
3149 // If index is still not a smi, it must be out of range.
3150 STATIC_ASSERT(kSmiTag == 0);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003151 __ JumpIfNotSmi(index_, index_out_of_range_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003152 // Otherwise, return to the fast path.
3153 __ jmp(&got_smi_index_);
3154
3155 // Call runtime. We get here when the receiver is a string and the
3156 // index is a number, but the code of getting the actual character
3157 // is too complex (e.g., when the string needs to be flattened).
3158 __ bind(&call_runtime_);
3159 call_helper.BeforeCall(masm);
3160 __ push(object_);
erikcorry0ad885c2011-11-21 13:51:57 +00003161 __ SmiTag(index_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003162 __ push(index_);
3163 __ CallRuntime(Runtime::kStringCharCodeAt, 2);
3164 if (!result_.is(eax)) {
3165 __ mov(result_, eax);
3166 }
3167 call_helper.AfterCall(masm);
3168 __ jmp(&exit_);
3169
danno@chromium.org59400602013-08-13 17:09:37 +00003170 __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003171}
3172
3173
3174// -------------------------------------------------------------------------
3175// StringCharFromCodeGenerator
3176
3177void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
3178 // Fast case of Heap::LookupSingleCharacterStringFromCode.
3179 STATIC_ASSERT(kSmiTag == 0);
3180 STATIC_ASSERT(kSmiShiftSize == 0);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003181 ASSERT(IsPowerOf2(String::kMaxOneByteCharCode + 1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003182 __ test(code_,
3183 Immediate(kSmiTagMask |
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003184 ((~String::kMaxOneByteCharCode) << kSmiTagSize)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003185 __ j(not_zero, &slow_case_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003186
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003187 Factory* factory = masm->isolate()->factory();
3188 __ Set(result_, Immediate(factory->single_character_string_cache()));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003189 STATIC_ASSERT(kSmiTag == 0);
3190 STATIC_ASSERT(kSmiTagSize == 1);
3191 STATIC_ASSERT(kSmiShiftSize == 0);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003192 // At this point code register contains smi tagged ASCII char code.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003193 __ mov(result_, FieldOperand(result_,
3194 code_, times_half_pointer_size,
3195 FixedArray::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003196 __ cmp(result_, factory->undefined_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003197 __ j(equal, &slow_case_);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003198 __ bind(&exit_);
3199}
3200
3201
3202void StringCharFromCodeGenerator::GenerateSlow(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003203 MacroAssembler* masm,
3204 const RuntimeCallHelper& call_helper) {
danno@chromium.org59400602013-08-13 17:09:37 +00003205 __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003206
3207 __ bind(&slow_case_);
3208 call_helper.BeforeCall(masm);
3209 __ push(code_);
3210 __ CallRuntime(Runtime::kCharFromCode, 1);
3211 if (!result_.is(eax)) {
3212 __ mov(result_, eax);
3213 }
3214 call_helper.AfterCall(masm);
3215 __ jmp(&exit_);
3216
danno@chromium.org59400602013-08-13 17:09:37 +00003217 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003218}
3219
3220
ricow@chromium.org65fae842010-08-25 15:26:24 +00003221void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm,
3222 Register dest,
3223 Register src,
3224 Register count,
3225 Register scratch,
3226 bool ascii) {
3227 // Copy characters using rep movs of doublewords.
3228 // The destination is aligned on a 4 byte boundary because we are
3229 // copying to the beginning of a newly allocated string.
3230 ASSERT(dest.is(edi)); // rep movs destination
3231 ASSERT(src.is(esi)); // rep movs source
3232 ASSERT(count.is(ecx)); // rep movs count
3233 ASSERT(!scratch.is(dest));
3234 ASSERT(!scratch.is(src));
3235 ASSERT(!scratch.is(count));
3236
3237 // Nothing to do for zero characters.
3238 Label done;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003239 __ test(count, count);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003240 __ j(zero, &done);
3241
3242 // Make count the number of bytes to copy.
3243 if (!ascii) {
3244 __ shl(count, 1);
3245 }
3246
3247 // Don't enter the rep movs if there are less than 4 bytes to copy.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003248 Label last_bytes;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003249 __ test(count, Immediate(~3));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003250 __ j(zero, &last_bytes, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003251
3252 // Copy from edi to esi using rep movs instruction.
3253 __ mov(scratch, count);
3254 __ sar(count, 2); // Number of doublewords to copy.
3255 __ cld();
3256 __ rep_movs();
3257
3258 // Find number of bytes left.
3259 __ mov(count, scratch);
3260 __ and_(count, 3);
3261
3262 // Check if there are more bytes to copy.
3263 __ bind(&last_bytes);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003264 __ test(count, count);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003265 __ j(zero, &done);
3266
3267 // Copy remaining characters.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003268 Label loop;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003269 __ bind(&loop);
3270 __ mov_b(scratch, Operand(src, 0));
3271 __ mov_b(Operand(dest, 0), scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003272 __ add(src, Immediate(1));
3273 __ add(dest, Immediate(1));
3274 __ sub(count, Immediate(1));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003275 __ j(not_zero, &loop);
3276
3277 __ bind(&done);
3278}
3279
3280
ricow@chromium.org65fae842010-08-25 15:26:24 +00003281void StringHelper::GenerateHashInit(MacroAssembler* masm,
3282 Register hash,
3283 Register character,
3284 Register scratch) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00003285 // hash = (seed + character) + ((seed + character) << 10);
3286 if (Serializer::enabled()) {
danno@chromium.org59400602013-08-13 17:09:37 +00003287 __ LoadRoot(scratch, Heap::kHashSeedRootIndex);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003288 __ SmiUntag(scratch);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00003289 __ add(scratch, character);
3290 __ mov(hash, scratch);
3291 __ shl(scratch, 10);
3292 __ add(hash, scratch);
3293 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003294 int32_t seed = masm->isolate()->heap()->HashSeed();
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00003295 __ lea(scratch, Operand(character, seed));
3296 __ shl(scratch, 10);
3297 __ lea(hash, Operand(scratch, character, times_1, seed));
3298 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003299 // hash ^= hash >> 6;
3300 __ mov(scratch, hash);
danno@chromium.org2c456792011-11-11 12:00:53 +00003301 __ shr(scratch, 6);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003302 __ xor_(hash, scratch);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003303}
3304
3305
3306void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
3307 Register hash,
3308 Register character,
3309 Register scratch) {
3310 // hash += character;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003311 __ add(hash, character);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003312 // hash += hash << 10;
3313 __ mov(scratch, hash);
3314 __ shl(scratch, 10);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003315 __ add(hash, scratch);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003316 // hash ^= hash >> 6;
3317 __ mov(scratch, hash);
danno@chromium.org2c456792011-11-11 12:00:53 +00003318 __ shr(scratch, 6);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003319 __ xor_(hash, scratch);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003320}
3321
3322
3323void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
3324 Register hash,
3325 Register scratch) {
3326 // hash += hash << 3;
3327 __ mov(scratch, hash);
3328 __ shl(scratch, 3);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003329 __ add(hash, scratch);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003330 // hash ^= hash >> 11;
3331 __ mov(scratch, hash);
danno@chromium.org2c456792011-11-11 12:00:53 +00003332 __ shr(scratch, 11);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003333 __ xor_(hash, scratch);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003334 // hash += hash << 15;
3335 __ mov(scratch, hash);
3336 __ shl(scratch, 15);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003337 __ add(hash, scratch);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003338
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003339 __ and_(hash, String::kHashBitMask);
danno@chromium.org2c456792011-11-11 12:00:53 +00003340
ricow@chromium.org65fae842010-08-25 15:26:24 +00003341 // if (hash == 0) hash = 27;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003342 Label hash_not_zero;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003343 __ j(not_zero, &hash_not_zero, Label::kNear);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003344 __ mov(hash, Immediate(StringHasher::kZeroHash));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003345 __ bind(&hash_not_zero);
3346}
3347
3348
3349void SubStringStub::Generate(MacroAssembler* masm) {
3350 Label runtime;
3351
3352 // Stack frame on entry.
3353 // esp[0]: return address
3354 // esp[4]: to
3355 // esp[8]: from
3356 // esp[12]: string
3357
3358 // Make sure first argument is a string.
3359 __ mov(eax, Operand(esp, 3 * kPointerSize));
3360 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003361 __ JumpIfSmi(eax, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003362 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx);
3363 __ j(NegateCondition(is_string), &runtime);
3364
3365 // eax: string
3366 // ebx: instance type
3367
3368 // Calculate length of sub string using the smi values.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003369 __ mov(ecx, Operand(esp, 1 * kPointerSize)); // To index.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003370 __ JumpIfNotSmi(ecx, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003371 __ mov(edx, Operand(esp, 2 * kPointerSize)); // From index.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003372 __ JumpIfNotSmi(edx, &runtime);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003373 __ sub(ecx, edx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003374 __ cmp(ecx, FieldOperand(eax, String::kLengthOffset));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003375 Label not_original_string;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003376 // Shorter than original string's length: an actual substring.
3377 __ j(below, &not_original_string, Label::kNear);
3378 // Longer than original string's length or negative: unsafe arguments.
3379 __ j(above, &runtime);
3380 // Return original string.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003381 Counters* counters = masm->isolate()->counters();
3382 __ IncrementCounter(counters->sub_string_native(), 1);
3383 __ ret(3 * kPointerSize);
3384 __ bind(&not_original_string);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003385
ulan@chromium.org2e04b582013-02-21 14:06:02 +00003386 Label single_char;
3387 __ cmp(ecx, Immediate(Smi::FromInt(1)));
3388 __ j(equal, &single_char);
3389
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003390 // eax: string
3391 // ebx: instance type
3392 // ecx: sub string length (smi)
3393 // edx: from index (smi)
3394 // Deal with different string types: update the index if necessary
3395 // and put the underlying string into edi.
3396 Label underlying_unpacked, sliced_string, seq_or_external_string;
3397 // If the string is not indirect, it can only be sequential or external.
3398 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
3399 STATIC_ASSERT(kIsIndirectStringMask != 0);
3400 __ test(ebx, Immediate(kIsIndirectStringMask));
3401 __ j(zero, &seq_or_external_string, Label::kNear);
3402
3403 Factory* factory = masm->isolate()->factory();
3404 __ test(ebx, Immediate(kSlicedNotConsMask));
3405 __ j(not_zero, &sliced_string, Label::kNear);
3406 // Cons string. Check whether it is flat, then fetch first part.
3407 // Flat cons strings have an empty second part.
3408 __ cmp(FieldOperand(eax, ConsString::kSecondOffset),
3409 factory->empty_string());
3410 __ j(not_equal, &runtime);
3411 __ mov(edi, FieldOperand(eax, ConsString::kFirstOffset));
3412 // Update instance type.
3413 __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
3414 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
3415 __ jmp(&underlying_unpacked, Label::kNear);
3416
3417 __ bind(&sliced_string);
3418 // Sliced string. Fetch parent and adjust start index by offset.
3419 __ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset));
3420 __ mov(edi, FieldOperand(eax, SlicedString::kParentOffset));
3421 // Update instance type.
3422 __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
3423 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
3424 __ jmp(&underlying_unpacked, Label::kNear);
3425
3426 __ bind(&seq_or_external_string);
3427 // Sequential or external string. Just move string to the expected register.
3428 __ mov(edi, eax);
3429
3430 __ bind(&underlying_unpacked);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003431
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003432 if (FLAG_string_slices) {
3433 Label copy_routine;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003434 // edi: underlying subject string
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003435 // ebx: instance type of underlying subject string
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003436 // edx: adjusted start index (smi)
3437 // ecx: length (smi)
3438 __ cmp(ecx, Immediate(Smi::FromInt(SlicedString::kMinLength)));
3439 // Short slice. Copy instead of slicing.
3440 __ j(less, &copy_routine);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003441 // Allocate new sliced string. At this point we do not reload the instance
3442 // type including the string encoding because we simply rely on the info
3443 // provided by the original string. It does not matter if the original
3444 // string's encoding is wrong because we always have to recheck encoding of
3445 // the newly created string's parent anyways due to externalized strings.
3446 Label two_byte_slice, set_slice_header;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003447 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003448 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
3449 __ test(ebx, Immediate(kStringEncodingMask));
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003450 __ j(zero, &two_byte_slice, Label::kNear);
3451 __ AllocateAsciiSlicedString(eax, ebx, no_reg, &runtime);
3452 __ jmp(&set_slice_header, Label::kNear);
3453 __ bind(&two_byte_slice);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003454 __ AllocateTwoByteSlicedString(eax, ebx, no_reg, &runtime);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003455 __ bind(&set_slice_header);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003456 __ mov(FieldOperand(eax, SlicedString::kLengthOffset), ecx);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003457 __ mov(FieldOperand(eax, SlicedString::kHashFieldOffset),
3458 Immediate(String::kEmptyHashField));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003459 __ mov(FieldOperand(eax, SlicedString::kParentOffset), edi);
3460 __ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003461 __ IncrementCounter(counters->sub_string_native(), 1);
3462 __ ret(3 * kPointerSize);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003463
3464 __ bind(&copy_routine);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003465 }
3466
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003467 // edi: underlying subject string
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003468 // ebx: instance type of underlying subject string
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003469 // edx: adjusted start index (smi)
3470 // ecx: length (smi)
3471 // The subject string can only be external or sequential string of either
3472 // encoding at this point.
3473 Label two_byte_sequential, runtime_drop_two, sequential_string;
3474 STATIC_ASSERT(kExternalStringTag != 0);
3475 STATIC_ASSERT(kSeqStringTag == 0);
3476 __ test_b(ebx, kExternalStringTag);
3477 __ j(zero, &sequential_string);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003478
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003479 // Handle external string.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003480 // Rule out short external strings.
3481 STATIC_CHECK(kShortExternalStringTag != 0);
3482 __ test_b(ebx, kShortExternalStringMask);
3483 __ j(not_zero, &runtime);
3484 __ mov(edi, FieldOperand(edi, ExternalString::kResourceDataOffset));
3485 // Move the pointer so that offset-wise, it looks like a sequential string.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003486 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003487 __ sub(edi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
3488
3489 __ bind(&sequential_string);
3490 // Stash away (adjusted) index and (underlying) string.
3491 __ push(edx);
3492 __ push(edi);
3493 __ SmiUntag(ecx);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003494 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003495 __ test_b(ebx, kStringEncodingMask);
3496 __ j(zero, &two_byte_sequential);
3497
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003498 // Sequential ASCII string. Allocate the result.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003499 __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime_drop_two);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003500
3501 // eax: result string
3502 // ecx: result string length
3503 __ mov(edx, esi); // esi used by following code.
3504 // Locate first character of result.
3505 __ mov(edi, eax);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003506 __ add(edi, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003507 // Load string argument and locate character of sub string start.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003508 __ pop(esi);
3509 __ pop(ebx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003510 __ SmiUntag(ebx);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003511 __ lea(esi, FieldOperand(esi, ebx, times_1, SeqOneByteString::kHeaderSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003512
3513 // eax: result string
3514 // ecx: result length
3515 // edx: original value of esi
3516 // edi: first character of result
3517 // esi: character of sub string start
3518 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true);
3519 __ mov(esi, edx); // Restore esi.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003520 __ IncrementCounter(counters->sub_string_native(), 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003521 __ ret(3 * kPointerSize);
3522
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003523 __ bind(&two_byte_sequential);
3524 // Sequential two-byte string. Allocate the result.
3525 __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime_drop_two);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003526
3527 // eax: result string
3528 // ecx: result string length
3529 __ mov(edx, esi); // esi used by following code.
3530 // Locate first character of result.
3531 __ mov(edi, eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003532 __ add(edi,
ricow@chromium.org65fae842010-08-25 15:26:24 +00003533 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
3534 // Load string argument and locate character of sub string start.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003535 __ pop(esi);
3536 __ pop(ebx);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003537 // As from is a smi it is 2 times the value which matches the size of a two
3538 // byte character.
3539 STATIC_ASSERT(kSmiTag == 0);
3540 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003541 __ lea(esi, FieldOperand(esi, ebx, times_1, SeqTwoByteString::kHeaderSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003542
3543 // eax: result string
3544 // ecx: result length
3545 // edx: original value of esi
3546 // edi: first character of result
3547 // esi: character of sub string start
3548 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false);
3549 __ mov(esi, edx); // Restore esi.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003550 __ IncrementCounter(counters->sub_string_native(), 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003551 __ ret(3 * kPointerSize);
3552
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003553 // Drop pushed values on the stack before tail call.
3554 __ bind(&runtime_drop_two);
3555 __ Drop(2);
3556
ricow@chromium.org65fae842010-08-25 15:26:24 +00003557 // Just jump to runtime to create the sub string.
3558 __ bind(&runtime);
3559 __ TailCallRuntime(Runtime::kSubString, 3, 1);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00003560
3561 __ bind(&single_char);
3562 // eax: string
3563 // ebx: instance type
3564 // ecx: sub string length (smi)
3565 // edx: from index (smi)
3566 StringCharAtGenerator generator(
3567 eax, edx, ecx, eax, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
3568 generator.GenerateFast(masm);
3569 __ ret(3 * kPointerSize);
3570 generator.SkipSlow(masm, &runtime);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003571}
3572
3573
lrn@chromium.org1c092762011-05-09 09:42:16 +00003574void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm,
3575 Register left,
3576 Register right,
3577 Register scratch1,
3578 Register scratch2) {
3579 Register length = scratch1;
3580
3581 // Compare lengths.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003582 Label strings_not_equal, check_zero_length;
lrn@chromium.org1c092762011-05-09 09:42:16 +00003583 __ mov(length, FieldOperand(left, String::kLengthOffset));
3584 __ cmp(length, FieldOperand(right, String::kLengthOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003585 __ j(equal, &check_zero_length, Label::kNear);
lrn@chromium.org1c092762011-05-09 09:42:16 +00003586 __ bind(&strings_not_equal);
3587 __ Set(eax, Immediate(Smi::FromInt(NOT_EQUAL)));
3588 __ ret(0);
3589
3590 // Check if the length is zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003591 Label compare_chars;
lrn@chromium.org1c092762011-05-09 09:42:16 +00003592 __ bind(&check_zero_length);
3593 STATIC_ASSERT(kSmiTag == 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003594 __ test(length, length);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003595 __ j(not_zero, &compare_chars, Label::kNear);
lrn@chromium.org1c092762011-05-09 09:42:16 +00003596 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
3597 __ ret(0);
3598
3599 // Compare characters.
3600 __ bind(&compare_chars);
3601 GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2,
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003602 &strings_not_equal, Label::kNear);
lrn@chromium.org1c092762011-05-09 09:42:16 +00003603
3604 // Characters are equal.
3605 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
3606 __ ret(0);
3607}
3608
3609
ricow@chromium.org65fae842010-08-25 15:26:24 +00003610void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
3611 Register left,
3612 Register right,
3613 Register scratch1,
3614 Register scratch2,
3615 Register scratch3) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003616 Counters* counters = masm->isolate()->counters();
3617 __ IncrementCounter(counters->string_compare_native(), 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003618
3619 // Find minimum length.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003620 Label left_shorter;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003621 __ mov(scratch1, FieldOperand(left, String::kLengthOffset));
3622 __ mov(scratch3, scratch1);
3623 __ sub(scratch3, FieldOperand(right, String::kLengthOffset));
3624
3625 Register length_delta = scratch3;
3626
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003627 __ j(less_equal, &left_shorter, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003628 // Right string is shorter. Change scratch1 to be length of right string.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003629 __ sub(scratch1, length_delta);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003630 __ bind(&left_shorter);
3631
3632 Register min_length = scratch1;
3633
3634 // If either length is zero, just compare lengths.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003635 Label compare_lengths;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003636 __ test(min_length, min_length);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003637 __ j(zero, &compare_lengths, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003638
lrn@chromium.org1c092762011-05-09 09:42:16 +00003639 // Compare characters.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003640 Label result_not_equal;
lrn@chromium.org1c092762011-05-09 09:42:16 +00003641 GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2,
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003642 &result_not_equal, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003643
3644 // Compare lengths - strings up to min-length are equal.
3645 __ bind(&compare_lengths);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003646 __ test(length_delta, length_delta);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003647 Label length_not_equal;
3648 __ j(not_zero, &length_not_equal, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003649
3650 // Result is EQUAL.
3651 STATIC_ASSERT(EQUAL == 0);
3652 STATIC_ASSERT(kSmiTag == 0);
3653 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
3654 __ ret(0);
3655
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003656 Label result_greater;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003657 Label result_less;
3658 __ bind(&length_not_equal);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003659 __ j(greater, &result_greater, Label::kNear);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003660 __ jmp(&result_less, Label::kNear);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003661 __ bind(&result_not_equal);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003662 __ j(above, &result_greater, Label::kNear);
3663 __ bind(&result_less);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003664
3665 // Result is LESS.
3666 __ Set(eax, Immediate(Smi::FromInt(LESS)));
3667 __ ret(0);
3668
3669 // Result is GREATER.
3670 __ bind(&result_greater);
3671 __ Set(eax, Immediate(Smi::FromInt(GREATER)));
3672 __ ret(0);
3673}
3674
3675
lrn@chromium.org1c092762011-05-09 09:42:16 +00003676void StringCompareStub::GenerateAsciiCharsCompareLoop(
3677 MacroAssembler* masm,
3678 Register left,
3679 Register right,
3680 Register length,
3681 Register scratch,
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003682 Label* chars_not_equal,
3683 Label::Distance chars_not_equal_near) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00003684 // Change index to run from -length to -1 by adding length to string
3685 // start. This means that loop ends when index reaches zero, which
3686 // doesn't need an additional compare.
3687 __ SmiUntag(length);
3688 __ lea(left,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003689 FieldOperand(left, length, times_1, SeqOneByteString::kHeaderSize));
lrn@chromium.org1c092762011-05-09 09:42:16 +00003690 __ lea(right,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003691 FieldOperand(right, length, times_1, SeqOneByteString::kHeaderSize));
lrn@chromium.org1c092762011-05-09 09:42:16 +00003692 __ neg(length);
3693 Register index = length; // index = -length;
3694
3695 // Compare loop.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003696 Label loop;
lrn@chromium.org1c092762011-05-09 09:42:16 +00003697 __ bind(&loop);
3698 __ mov_b(scratch, Operand(left, index, times_1, 0));
3699 __ cmpb(scratch, Operand(right, index, times_1, 0));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003700 __ j(not_equal, chars_not_equal, chars_not_equal_near);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003701 __ inc(index);
lrn@chromium.org1c092762011-05-09 09:42:16 +00003702 __ j(not_zero, &loop);
3703}
3704
3705
ricow@chromium.org65fae842010-08-25 15:26:24 +00003706void StringCompareStub::Generate(MacroAssembler* masm) {
3707 Label runtime;
3708
3709 // Stack frame on entry.
3710 // esp[0]: return address
3711 // esp[4]: right string
3712 // esp[8]: left string
3713
3714 __ mov(edx, Operand(esp, 2 * kPointerSize)); // left
3715 __ mov(eax, Operand(esp, 1 * kPointerSize)); // right
3716
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003717 Label not_same;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003718 __ cmp(edx, eax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003719 __ j(not_equal, &not_same, Label::kNear);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003720 STATIC_ASSERT(EQUAL == 0);
3721 STATIC_ASSERT(kSmiTag == 0);
3722 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003723 __ IncrementCounter(masm->isolate()->counters()->string_compare_native(), 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003724 __ ret(2 * kPointerSize);
3725
3726 __ bind(&not_same);
3727
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003728 // Check that both objects are sequential ASCII strings.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003729 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime);
3730
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003731 // Compare flat ASCII strings.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003732 // Drop arguments from the stack.
3733 __ pop(ecx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003734 __ add(esp, Immediate(2 * kPointerSize));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003735 __ push(ecx);
3736 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi);
3737
3738 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
3739 // tagged as a small integer.
3740 __ bind(&runtime);
3741 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
3742}
3743
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003744
machenbach@chromium.orgc8cbc432014-01-21 09:01:57 +00003745void ArrayPushStub::Generate(MacroAssembler* masm) {
3746 int argc = arguments_count();
3747
3748 if (argc == 0) {
3749 // Noop, return the length.
3750 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
3751 __ ret((argc + 1) * kPointerSize);
3752 return;
3753 }
3754
3755 Isolate* isolate = masm->isolate();
3756
3757 if (argc != 1) {
3758 __ TailCallExternalReference(
3759 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
3760 return;
3761 }
3762
3763 Label call_builtin, attempt_to_grow_elements, with_write_barrier;
3764
3765 // Get the elements array of the object.
3766 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
3767
3768 if (IsFastSmiOrObjectElementsKind(elements_kind())) {
3769 // Check that the elements are in fast mode and writable.
3770 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
3771 isolate->factory()->fixed_array_map());
3772 __ j(not_equal, &call_builtin);
3773 }
3774
3775 // Get the array's length into eax and calculate new length.
3776 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
3777 STATIC_ASSERT(kSmiTagSize == 1);
3778 STATIC_ASSERT(kSmiTag == 0);
3779 __ add(eax, Immediate(Smi::FromInt(argc)));
3780
3781 // Get the elements' length into ecx.
3782 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
3783
3784 // Check if we could survive without allocation.
3785 __ cmp(eax, ecx);
3786
3787 if (IsFastSmiOrObjectElementsKind(elements_kind())) {
3788 __ j(greater, &attempt_to_grow_elements);
3789
3790 // Check if value is a smi.
3791 __ mov(ecx, Operand(esp, argc * kPointerSize));
3792 __ JumpIfNotSmi(ecx, &with_write_barrier);
3793
3794 // Store the value.
3795 __ mov(FieldOperand(edi, eax, times_half_pointer_size,
3796 FixedArray::kHeaderSize - argc * kPointerSize),
3797 ecx);
3798 } else {
3799 __ j(greater, &call_builtin);
3800
3801 __ mov(ecx, Operand(esp, argc * kPointerSize));
3802 __ StoreNumberToDoubleElements(
3803 ecx, edi, eax, ecx, xmm0, &call_builtin, true, argc * kDoubleSize);
3804 }
3805
3806 // Save new length.
3807 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
3808 __ ret((argc + 1) * kPointerSize);
3809
3810 if (IsFastDoubleElementsKind(elements_kind())) {
3811 __ bind(&call_builtin);
3812 __ TailCallExternalReference(
3813 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
3814 return;
3815 }
3816
3817 __ bind(&with_write_barrier);
3818
3819 if (IsFastSmiElementsKind(elements_kind())) {
3820 if (FLAG_trace_elements_transitions) __ jmp(&call_builtin);
3821
3822 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
3823 isolate->factory()->heap_number_map());
3824 __ j(equal, &call_builtin);
3825
3826 ElementsKind target_kind = IsHoleyElementsKind(elements_kind())
3827 ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS;
3828 __ mov(ebx, ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX));
3829 __ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
3830 __ mov(ebx, ContextOperand(ebx, Context::JS_ARRAY_MAPS_INDEX));
3831 const int header_size = FixedArrayBase::kHeaderSize;
3832 // Verify that the object can be transitioned in place.
3833 const int origin_offset = header_size + elements_kind() * kPointerSize;
3834 __ mov(edi, FieldOperand(ebx, origin_offset));
3835 __ cmp(edi, FieldOperand(edx, HeapObject::kMapOffset));
3836 __ j(not_equal, &call_builtin);
3837
3838 const int target_offset = header_size + target_kind * kPointerSize;
3839 __ mov(ebx, FieldOperand(ebx, target_offset));
3840 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
3841 masm, DONT_TRACK_ALLOCATION_SITE, NULL);
3842 // Restore edi used as a scratch register for the write barrier used while
3843 // setting the map.
3844 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
3845 }
3846
3847 // Save new length.
3848 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
3849
3850 // Store the value.
3851 __ lea(edx, FieldOperand(edi, eax, times_half_pointer_size,
3852 FixedArray::kHeaderSize - argc * kPointerSize));
3853 __ mov(Operand(edx, 0), ecx);
3854
3855 __ RecordWrite(edi, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
3856 OMIT_SMI_CHECK);
3857
3858 __ ret((argc + 1) * kPointerSize);
3859
3860 __ bind(&attempt_to_grow_elements);
3861 if (!FLAG_inline_new) {
3862 __ bind(&call_builtin);
3863 __ TailCallExternalReference(
3864 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
3865 return;
3866 }
3867
3868 __ mov(ebx, Operand(esp, argc * kPointerSize));
3869 // Growing elements that are SMI-only requires special handling in case the
3870 // new element is non-Smi. For now, delegate to the builtin.
3871 if (IsFastSmiElementsKind(elements_kind())) {
3872 __ JumpIfNotSmi(ebx, &call_builtin);
3873 }
3874
3875 // We could be lucky and the elements array could be at the top of new-space.
3876 // In this case we can just grow it in place by moving the allocation pointer
3877 // up.
3878 ExternalReference new_space_allocation_top =
3879 ExternalReference::new_space_allocation_top_address(isolate);
3880 ExternalReference new_space_allocation_limit =
3881 ExternalReference::new_space_allocation_limit_address(isolate);
3882
3883 const int kAllocationDelta = 4;
3884 ASSERT(kAllocationDelta >= argc);
3885 // Load top.
3886 __ mov(ecx, Operand::StaticVariable(new_space_allocation_top));
3887
3888 // Check if it's the end of elements.
3889 __ lea(edx, FieldOperand(edi, eax, times_half_pointer_size,
3890 FixedArray::kHeaderSize - argc * kPointerSize));
3891 __ cmp(edx, ecx);
3892 __ j(not_equal, &call_builtin);
3893 __ add(ecx, Immediate(kAllocationDelta * kPointerSize));
3894 __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit));
3895 __ j(above, &call_builtin);
3896
3897 // We fit and could grow elements.
3898 __ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
3899
3900 // Push the argument...
3901 __ mov(Operand(edx, 0), ebx);
3902 // ... and fill the rest with holes.
3903 for (int i = 1; i < kAllocationDelta; i++) {
3904 __ mov(Operand(edx, i * kPointerSize),
3905 isolate->factory()->the_hole_value());
3906 }
3907
3908 if (IsFastObjectElementsKind(elements_kind())) {
3909 // We know the elements array is in new space so we don't need the
3910 // remembered set, but we just pushed a value onto it so we may have to tell
3911 // the incremental marker to rescan the object that we just grew. We don't
3912 // need to worry about the holes because they are in old space and already
3913 // marked black.
3914 __ RecordWrite(edi, edx, ebx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
3915 }
3916
3917 // Restore receiver to edx as finish sequence assumes it's here.
3918 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
3919
3920 // Increment element's and array's sizes.
3921 __ add(FieldOperand(edi, FixedArray::kLengthOffset),
3922 Immediate(Smi::FromInt(kAllocationDelta)));
3923
3924 // NOTE: This only happen in new-space, where we don't care about the
3925 // black-byte-count on pages. Otherwise we should update that too if the
3926 // object is black.
3927
3928 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
3929 __ ret((argc + 1) * kPointerSize);
3930
3931 __ bind(&call_builtin);
3932 __ TailCallExternalReference(
3933 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
3934}
3935
3936
ulan@chromium.org0f13e742014-01-03 15:51:11 +00003937void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
3938 // ----------- S t a t e -------------
3939 // -- edx : left
3940 // -- eax : right
3941 // -- esp[0] : return address
3942 // -----------------------------------
3943 Isolate* isolate = masm->isolate();
3944
3945 // Load ecx with the allocation site. We stick an undefined dummy value here
3946 // and replace it with the real allocation site later when we instantiate this
3947 // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
3948 __ mov(ecx, handle(isolate->heap()->undefined_value()));
3949
3950 // Make sure that we actually patched the allocation site.
3951 if (FLAG_debug_code) {
3952 __ test(ecx, Immediate(kSmiTagMask));
3953 __ Assert(not_equal, kExpectedAllocationSite);
3954 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
3955 isolate->factory()->allocation_site_map());
3956 __ Assert(equal, kExpectedAllocationSite);
3957 }
3958
3959 // Tail call into the stub that handles binary operations with allocation
3960 // sites.
3961 BinaryOpWithAllocationSiteStub stub(state_);
3962 __ TailCallStub(&stub);
3963}
3964
3965
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003966void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003967 ASSERT(state_ == CompareIC::SMI);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003968 Label miss;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003969 __ mov(ecx, edx);
3970 __ or_(ecx, eax);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003971 __ JumpIfNotSmi(ecx, &miss, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003972
3973 if (GetCondition() == equal) {
3974 // For equality we do not care about the sign of the result.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003975 __ sub(eax, edx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003976 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003977 Label done;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003978 __ sub(edx, eax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003979 __ j(no_overflow, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003980 // Correct sign of result in case of overflow.
3981 __ not_(edx);
3982 __ bind(&done);
3983 __ mov(eax, edx);
3984 }
3985 __ ret(0);
3986
3987 __ bind(&miss);
3988 GenerateMiss(masm);
3989}
3990
3991
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003992void ICCompareStub::GenerateNumbers(MacroAssembler* masm) {
3993 ASSERT(state_ == CompareIC::NUMBER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003994
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003995 Label generic_stub;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00003996 Label unordered, maybe_undefined1, maybe_undefined2;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003997 Label miss;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003998
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003999 if (left_ == CompareIC::SMI) {
4000 __ JumpIfNotSmi(edx, &miss);
4001 }
4002 if (right_ == CompareIC::SMI) {
4003 __ JumpIfNotSmi(eax, &miss);
4004 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004005
4006 // Inlining the double comparison and falling back to the general compare
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004007 // stub if NaN is involved or SSE2 or CMOV is unsupported.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004008 if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004009 CpuFeatureScope scope1(masm, SSE2);
4010 CpuFeatureScope scope2(masm, CMOV);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004011
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004012 // Load left and right operand.
4013 Label done, left, left_smi, right_smi;
4014 __ JumpIfSmi(eax, &right_smi, Label::kNear);
4015 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
4016 masm->isolate()->factory()->heap_number_map());
4017 __ j(not_equal, &maybe_undefined1, Label::kNear);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004018 __ movsd(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004019 __ jmp(&left, Label::kNear);
4020 __ bind(&right_smi);
4021 __ mov(ecx, eax); // Can't clobber eax because we can still jump away.
4022 __ SmiUntag(ecx);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004023 __ Cvtsi2sd(xmm1, ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004024
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004025 __ bind(&left);
4026 __ JumpIfSmi(edx, &left_smi, Label::kNear);
4027 __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
4028 masm->isolate()->factory()->heap_number_map());
4029 __ j(not_equal, &maybe_undefined2, Label::kNear);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004030 __ movsd(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004031 __ jmp(&done);
4032 __ bind(&left_smi);
4033 __ mov(ecx, edx); // Can't clobber edx because we can still jump away.
4034 __ SmiUntag(ecx);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004035 __ Cvtsi2sd(xmm0, ecx);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004036
4037 __ bind(&done);
4038 // Compare operands.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004039 __ ucomisd(xmm0, xmm1);
4040
4041 // Don't base result on EFLAGS when a NaN is involved.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004042 __ j(parity_even, &unordered, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004043
4044 // Return a result of -1, 0, or 1, based on EFLAGS.
4045 // Performing mov, because xor would destroy the flag register.
4046 __ mov(eax, 0); // equal
4047 __ mov(ecx, Immediate(Smi::FromInt(1)));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004048 __ cmov(above, eax, ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004049 __ mov(ecx, Immediate(Smi::FromInt(-1)));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004050 __ cmov(below, eax, ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004051 __ ret(0);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004052 } else {
4053 __ mov(ecx, edx);
4054 __ and_(ecx, eax);
4055 __ JumpIfSmi(ecx, &generic_stub, Label::kNear);
4056
4057 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
4058 masm->isolate()->factory()->heap_number_map());
4059 __ j(not_equal, &maybe_undefined1, Label::kNear);
4060 __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
4061 masm->isolate()->factory()->heap_number_map());
4062 __ j(not_equal, &maybe_undefined2, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004063 }
4064
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004065 __ bind(&unordered);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004066 __ bind(&generic_stub);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004067 ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC,
4068 CompareIC::GENERIC);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004069 __ jmp(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004070
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004071 __ bind(&maybe_undefined1);
4072 if (Token::IsOrderedRelationalCompareOp(op_)) {
4073 __ cmp(eax, Immediate(masm->isolate()->factory()->undefined_value()));
4074 __ j(not_equal, &miss);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004075 __ JumpIfSmi(edx, &unordered);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004076 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
4077 __ j(not_equal, &maybe_undefined2, Label::kNear);
4078 __ jmp(&unordered);
4079 }
4080
4081 __ bind(&maybe_undefined2);
4082 if (Token::IsOrderedRelationalCompareOp(op_)) {
4083 __ cmp(edx, Immediate(masm->isolate()->factory()->undefined_value()));
4084 __ j(equal, &unordered);
4085 }
4086
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004087 __ bind(&miss);
4088 GenerateMiss(masm);
4089}
4090
4091
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004092void ICCompareStub::GenerateInternalizedStrings(MacroAssembler* masm) {
4093 ASSERT(state_ == CompareIC::INTERNALIZED_STRING);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004094 ASSERT(GetCondition() == equal);
4095
4096 // Registers containing left and right operands respectively.
4097 Register left = edx;
4098 Register right = eax;
4099 Register tmp1 = ecx;
4100 Register tmp2 = ebx;
4101
4102 // Check that both operands are heap objects.
4103 Label miss;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004104 __ mov(tmp1, left);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004105 STATIC_ASSERT(kSmiTag == 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004106 __ and_(tmp1, right);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004107 __ JumpIfSmi(tmp1, &miss, Label::kNear);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004108
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004109 // Check that both operands are internalized strings.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004110 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
4111 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
4112 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
4113 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004114 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
4115 __ or_(tmp1, tmp2);
4116 __ test(tmp1, Immediate(kIsNotStringMask | kIsNotInternalizedMask));
4117 __ j(not_zero, &miss, Label::kNear);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004118
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004119 // Internalized strings are compared by identity.
4120 Label done;
4121 __ cmp(left, right);
4122 // Make sure eax is non-zero. At this point input operands are
4123 // guaranteed to be non-zero.
4124 ASSERT(right.is(eax));
4125 __ j(not_equal, &done, Label::kNear);
4126 STATIC_ASSERT(EQUAL == 0);
4127 STATIC_ASSERT(kSmiTag == 0);
4128 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
4129 __ bind(&done);
4130 __ ret(0);
4131
4132 __ bind(&miss);
4133 GenerateMiss(masm);
4134}
4135
4136
4137void ICCompareStub::GenerateUniqueNames(MacroAssembler* masm) {
4138 ASSERT(state_ == CompareIC::UNIQUE_NAME);
4139 ASSERT(GetCondition() == equal);
4140
4141 // Registers containing left and right operands respectively.
4142 Register left = edx;
4143 Register right = eax;
4144 Register tmp1 = ecx;
4145 Register tmp2 = ebx;
4146
4147 // Check that both operands are heap objects.
4148 Label miss;
4149 __ mov(tmp1, left);
4150 STATIC_ASSERT(kSmiTag == 0);
4151 __ and_(tmp1, right);
4152 __ JumpIfSmi(tmp1, &miss, Label::kNear);
4153
4154 // Check that both operands are unique names. This leaves the instance
4155 // types loaded in tmp1 and tmp2.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004156 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
4157 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
4158 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
4159 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
4160
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004161 __ JumpIfNotUniqueName(tmp1, &miss, Label::kNear);
4162 __ JumpIfNotUniqueName(tmp2, &miss, Label::kNear);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004163
4164 // Unique names are compared by identity.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004165 Label done;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004166 __ cmp(left, right);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004167 // Make sure eax is non-zero. At this point input operands are
4168 // guaranteed to be non-zero.
4169 ASSERT(right.is(eax));
4170 __ j(not_equal, &done, Label::kNear);
4171 STATIC_ASSERT(EQUAL == 0);
4172 STATIC_ASSERT(kSmiTag == 0);
4173 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
4174 __ bind(&done);
4175 __ ret(0);
4176
4177 __ bind(&miss);
4178 GenerateMiss(masm);
4179}
4180
4181
lrn@chromium.org1c092762011-05-09 09:42:16 +00004182void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004183 ASSERT(state_ == CompareIC::STRING);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004184 Label miss;
4185
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004186 bool equality = Token::IsEqualityOp(op_);
4187
lrn@chromium.org1c092762011-05-09 09:42:16 +00004188 // Registers containing left and right operands respectively.
4189 Register left = edx;
4190 Register right = eax;
4191 Register tmp1 = ecx;
4192 Register tmp2 = ebx;
4193 Register tmp3 = edi;
4194
4195 // Check that both operands are heap objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004196 __ mov(tmp1, left);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004197 STATIC_ASSERT(kSmiTag == 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004198 __ and_(tmp1, right);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004199 __ JumpIfSmi(tmp1, &miss);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004200
4201 // Check that both operands are strings. This leaves the instance
4202 // types loaded in tmp1 and tmp2.
4203 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
4204 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
4205 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
4206 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
4207 __ mov(tmp3, tmp1);
4208 STATIC_ASSERT(kNotStringTag != 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004209 __ or_(tmp3, tmp2);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004210 __ test(tmp3, Immediate(kIsNotStringMask));
4211 __ j(not_zero, &miss);
4212
4213 // Fast check for identical strings.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004214 Label not_same;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004215 __ cmp(left, right);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004216 __ j(not_equal, &not_same, Label::kNear);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004217 STATIC_ASSERT(EQUAL == 0);
4218 STATIC_ASSERT(kSmiTag == 0);
4219 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
4220 __ ret(0);
4221
4222 // Handle not identical strings.
4223 __ bind(&not_same);
4224
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004225 // Check that both strings are internalized. If they are, we're done
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004226 // because we already know they are not identical. But in the case of
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004227 // non-equality compare, we still need to determine the order. We
4228 // also know they are both strings.
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004229 if (equality) {
4230 Label do_compare;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004231 STATIC_ASSERT(kInternalizedTag == 0);
4232 __ or_(tmp1, tmp2);
4233 __ test(tmp1, Immediate(kIsNotInternalizedMask));
4234 __ j(not_zero, &do_compare, Label::kNear);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004235 // Make sure eax is non-zero. At this point input operands are
4236 // guaranteed to be non-zero.
4237 ASSERT(right.is(eax));
4238 __ ret(0);
4239 __ bind(&do_compare);
4240 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00004241
4242 // Check that both strings are sequential ASCII.
4243 Label runtime;
lrn@chromium.org1c092762011-05-09 09:42:16 +00004244 __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime);
4245
4246 // Compare flat ASCII strings. Returns when done.
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004247 if (equality) {
4248 StringCompareStub::GenerateFlatAsciiStringEquals(
4249 masm, left, right, tmp1, tmp2);
4250 } else {
4251 StringCompareStub::GenerateCompareFlatAsciiStrings(
4252 masm, left, right, tmp1, tmp2, tmp3);
4253 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00004254
4255 // Handle more complex cases in runtime.
4256 __ bind(&runtime);
4257 __ pop(tmp1); // Return address.
4258 __ push(left);
4259 __ push(right);
4260 __ push(tmp1);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00004261 if (equality) {
4262 __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
4263 } else {
4264 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
4265 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00004266
4267 __ bind(&miss);
4268 GenerateMiss(masm);
4269}
4270
4271
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004272void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004273 ASSERT(state_ == CompareIC::OBJECT);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004274 Label miss;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004275 __ mov(ecx, edx);
4276 __ and_(ecx, eax);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004277 __ JumpIfSmi(ecx, &miss, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004278
4279 __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004280 __ j(not_equal, &miss, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004281 __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004282 __ j(not_equal, &miss, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004283
4284 ASSERT(GetCondition() == equal);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004285 __ sub(eax, edx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004286 __ ret(0);
4287
4288 __ bind(&miss);
4289 GenerateMiss(masm);
4290}
4291
4292
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004293void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
4294 Label miss;
4295 __ mov(ecx, edx);
4296 __ and_(ecx, eax);
4297 __ JumpIfSmi(ecx, &miss, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004298
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004299 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
4300 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
4301 __ cmp(ecx, known_map_);
4302 __ j(not_equal, &miss, Label::kNear);
4303 __ cmp(ebx, known_map_);
4304 __ j(not_equal, &miss, Label::kNear);
4305
4306 __ sub(eax, edx);
4307 __ ret(0);
4308
4309 __ bind(&miss);
4310 GenerateMiss(masm);
4311}
4312
4313
4314void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004315 {
4316 // Call the runtime system in a fresh internal frame.
4317 ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss),
4318 masm->isolate());
4319 FrameScope scope(masm, StackFrame::INTERNAL);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004320 __ push(edx); // Preserve edx and eax.
4321 __ push(eax);
4322 __ push(edx); // And also use them as the arguments.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004323 __ push(eax);
4324 __ push(Immediate(Smi::FromInt(op_)));
4325 __ CallExternalReference(miss, 3);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004326 // Compute the entry point of the rewritten stub.
4327 __ lea(edi, FieldOperand(eax, Code::kHeaderSize));
4328 __ pop(eax);
4329 __ pop(edx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004330 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004331
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004332 // Do a tail call to the rewritten stub.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004333 __ jmp(edi);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004334}
4335
4336
lrn@chromium.org1c092762011-05-09 09:42:16 +00004337// Helper function used to check that the dictionary doesn't contain
4338// the property. This function may return false negatives, so miss_label
4339// must always call a backup property check that is complete.
4340// This function is safe to call if the receiver has fast properties.
ulan@chromium.org750145a2013-03-07 15:14:13 +00004341// Name must be a unique name and receiver must be a heap object.
4342void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
4343 Label* miss,
4344 Label* done,
4345 Register properties,
4346 Handle<Name> name,
4347 Register r0) {
4348 ASSERT(name->IsUniqueName());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004349
4350 // If names of slots in range from 1 to kProbes - 1 for the hash value are
4351 // not equal to the name and kProbes-th slot is not used (its name is the
4352 // undefined value), it guarantees the hash table doesn't contain the
4353 // property. It's true even if some slots represent deleted properties
ulan@chromium.org967e2702012-02-28 09:49:15 +00004354 // (their names are the hole value).
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004355 for (int i = 0; i < kInlinedProbes; i++) {
4356 // Compute the masked index: (hash + i + i * i) & mask.
4357 Register index = r0;
4358 // Capacity is smi 2^n.
4359 __ mov(index, FieldOperand(properties, kCapacityOffset));
4360 __ dec(index);
4361 __ and_(index,
4362 Immediate(Smi::FromInt(name->Hash() +
ulan@chromium.org750145a2013-03-07 15:14:13 +00004363 NameDictionary::GetProbeOffset(i))));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004364
4365 // Scale the index by multiplying by the entry size.
ulan@chromium.org750145a2013-03-07 15:14:13 +00004366 ASSERT(NameDictionary::kEntrySize == 3);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004367 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3.
4368 Register entity_name = r0;
4369 // Having undefined at this place means the name is not contained.
4370 ASSERT_EQ(kSmiTagSize, 1);
4371 __ mov(entity_name, Operand(properties, index, times_half_pointer_size,
4372 kElementsStartOffset - kHeapObjectTag));
4373 __ cmp(entity_name, masm->isolate()->factory()->undefined_value());
4374 __ j(equal, done);
4375
4376 // Stop if found the property.
ulan@chromium.org750145a2013-03-07 15:14:13 +00004377 __ cmp(entity_name, Handle<Name>(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004378 __ j(equal, miss);
4379
ulan@chromium.org750145a2013-03-07 15:14:13 +00004380 Label good;
ulan@chromium.org967e2702012-02-28 09:49:15 +00004381 // Check for the hole and skip.
4382 __ cmp(entity_name, masm->isolate()->factory()->the_hole_value());
ulan@chromium.org750145a2013-03-07 15:14:13 +00004383 __ j(equal, &good, Label::kNear);
ulan@chromium.org967e2702012-02-28 09:49:15 +00004384
ulan@chromium.org750145a2013-03-07 15:14:13 +00004385 // Check if the entry name is not a unique name.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004386 __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004387 __ JumpIfNotUniqueName(FieldOperand(entity_name, Map::kInstanceTypeOffset),
4388 miss);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004389 __ bind(&good);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004390 }
4391
ulan@chromium.org750145a2013-03-07 15:14:13 +00004392 NameDictionaryLookupStub stub(properties, r0, r0, NEGATIVE_LOOKUP);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004393 __ push(Immediate(Handle<Object>(name)));
4394 __ push(Immediate(name->Hash()));
4395 __ CallStub(&stub);
4396 __ test(r0, r0);
4397 __ j(not_zero, miss);
4398 __ jmp(done);
4399}
4400
4401
ulan@chromium.org750145a2013-03-07 15:14:13 +00004402// Probe the name dictionary in the |elements| register. Jump to the
lrn@chromium.org1c092762011-05-09 09:42:16 +00004403// |done| label if a property with the given name is found leaving the
4404// index into the dictionary in |r0|. Jump to the |miss| label
4405// otherwise.
ulan@chromium.org750145a2013-03-07 15:14:13 +00004406void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
4407 Label* miss,
4408 Label* done,
4409 Register elements,
4410 Register name,
4411 Register r0,
4412 Register r1) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00004413 ASSERT(!elements.is(r0));
4414 ASSERT(!elements.is(r1));
4415 ASSERT(!name.is(r0));
4416 ASSERT(!name.is(r1));
4417
ulan@chromium.org750145a2013-03-07 15:14:13 +00004418 __ AssertName(name);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004419
4420 __ mov(r1, FieldOperand(elements, kCapacityOffset));
4421 __ shr(r1, kSmiTagSize); // convert smi to int
4422 __ dec(r1);
4423
4424 // Generate an unrolled loop that performs a few probes before
4425 // giving up. Measurements done on Gmail indicate that 2 probes
4426 // cover ~93% of loads from dictionaries.
4427 for (int i = 0; i < kInlinedProbes; i++) {
4428 // Compute the masked index: (hash + i + i * i) & mask.
ulan@chromium.org750145a2013-03-07 15:14:13 +00004429 __ mov(r0, FieldOperand(name, Name::kHashFieldOffset));
4430 __ shr(r0, Name::kHashShift);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004431 if (i > 0) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004432 __ add(r0, Immediate(NameDictionary::GetProbeOffset(i)));
lrn@chromium.org1c092762011-05-09 09:42:16 +00004433 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004434 __ and_(r0, r1);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004435
4436 // Scale the index by multiplying by the entry size.
ulan@chromium.org750145a2013-03-07 15:14:13 +00004437 ASSERT(NameDictionary::kEntrySize == 3);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004438 __ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3
4439
4440 // Check if the key is identical to the name.
4441 __ cmp(name, Operand(elements,
4442 r0,
4443 times_4,
4444 kElementsStartOffset - kHeapObjectTag));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004445 __ j(equal, done);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004446 }
4447
ulan@chromium.org750145a2013-03-07 15:14:13 +00004448 NameDictionaryLookupStub stub(elements, r1, r0, POSITIVE_LOOKUP);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004449 __ push(name);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004450 __ mov(r0, FieldOperand(name, Name::kHashFieldOffset));
4451 __ shr(r0, Name::kHashShift);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004452 __ push(r0);
4453 __ CallStub(&stub);
4454
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004455 __ test(r1, r1);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004456 __ j(zero, miss);
4457 __ jmp(done);
4458}
4459
4460
ulan@chromium.org750145a2013-03-07 15:14:13 +00004461void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004462 // This stub overrides SometimesSetsUpAFrame() to return false. That means
4463 // we cannot call anything that could cause a GC from this stub.
lrn@chromium.org1c092762011-05-09 09:42:16 +00004464 // Stack frame on entry:
4465 // esp[0 * kPointerSize]: return address.
4466 // esp[1 * kPointerSize]: key's hash.
4467 // esp[2 * kPointerSize]: key.
4468 // Registers:
ulan@chromium.org750145a2013-03-07 15:14:13 +00004469 // dictionary_: NameDictionary to probe.
lrn@chromium.org1c092762011-05-09 09:42:16 +00004470 // result_: used as scratch.
4471 // index_: will hold an index of entry if lookup is successful.
4472 // might alias with result_.
4473 // Returns:
4474 // result_ is zero if lookup failed, non zero otherwise.
4475
4476 Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
4477
4478 Register scratch = result_;
4479
4480 __ mov(scratch, FieldOperand(dictionary_, kCapacityOffset));
4481 __ dec(scratch);
4482 __ SmiUntag(scratch);
4483 __ push(scratch);
4484
4485 // If names of slots in range from 1 to kProbes - 1 for the hash value are
4486 // not equal to the name and kProbes-th slot is not used (its name is the
4487 // undefined value), it guarantees the hash table doesn't contain the
4488 // property. It's true even if some slots represent deleted properties
4489 // (their names are the null value).
4490 for (int i = kInlinedProbes; i < kTotalProbes; i++) {
4491 // Compute the masked index: (hash + i + i * i) & mask.
4492 __ mov(scratch, Operand(esp, 2 * kPointerSize));
4493 if (i > 0) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004494 __ add(scratch, Immediate(NameDictionary::GetProbeOffset(i)));
lrn@chromium.org1c092762011-05-09 09:42:16 +00004495 }
4496 __ and_(scratch, Operand(esp, 0));
4497
4498 // Scale the index by multiplying by the entry size.
ulan@chromium.org750145a2013-03-07 15:14:13 +00004499 ASSERT(NameDictionary::kEntrySize == 3);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004500 __ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3.
4501
4502 // Having undefined at this place means the name is not contained.
4503 ASSERT_EQ(kSmiTagSize, 1);
4504 __ mov(scratch, Operand(dictionary_,
4505 index_,
4506 times_pointer_size,
4507 kElementsStartOffset - kHeapObjectTag));
4508 __ cmp(scratch, masm->isolate()->factory()->undefined_value());
4509 __ j(equal, &not_in_dictionary);
4510
4511 // Stop if found the property.
4512 __ cmp(scratch, Operand(esp, 3 * kPointerSize));
4513 __ j(equal, &in_dictionary);
4514
4515 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004516 // If we hit a key that is not a unique name during negative
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004517 // lookup we have to bailout as this key might be equal to the
lrn@chromium.org1c092762011-05-09 09:42:16 +00004518 // key we are looking for.
4519
ulan@chromium.org750145a2013-03-07 15:14:13 +00004520 // Check if the entry name is not a unique name.
lrn@chromium.org1c092762011-05-09 09:42:16 +00004521 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004522 __ JumpIfNotUniqueName(FieldOperand(scratch, Map::kInstanceTypeOffset),
4523 &maybe_in_dictionary);
lrn@chromium.org1c092762011-05-09 09:42:16 +00004524 }
4525 }
4526
4527 __ bind(&maybe_in_dictionary);
4528 // If we are doing negative lookup then probing failure should be
4529 // treated as a lookup success. For positive lookup probing failure
4530 // should be treated as lookup failure.
4531 if (mode_ == POSITIVE_LOOKUP) {
4532 __ mov(result_, Immediate(0));
4533 __ Drop(1);
4534 __ ret(2 * kPointerSize);
4535 }
4536
4537 __ bind(&in_dictionary);
4538 __ mov(result_, Immediate(1));
4539 __ Drop(1);
4540 __ ret(2 * kPointerSize);
4541
4542 __ bind(&not_in_dictionary);
4543 __ mov(result_, Immediate(0));
4544 __ Drop(1);
4545 __ ret(2 * kPointerSize);
4546}
4547
4548
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004549void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
4550 Isolate* isolate) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004551 StoreBufferOverflowStub stub(kDontSaveFPRegs);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00004552 stub.GetCode(isolate);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004553 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004554 StoreBufferOverflowStub stub2(kSaveFPRegs);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00004555 stub2.GetCode(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004556 }
4557}
4558
4559
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004560bool CodeStub::CanUseFPRegisters() {
4561 return CpuFeatures::IsSupported(SSE2);
4562}
4563
4564
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004565// Takes the input in 3 registers: address_ value_ and object_. A pointer to
4566// the value has just been written into the object, now this stub makes sure
4567// we keep the GC informed. The word in the object where the value has been
4568// written is in the address register.
4569void RecordWriteStub::Generate(MacroAssembler* masm) {
4570 Label skip_to_incremental_noncompacting;
4571 Label skip_to_incremental_compacting;
4572
4573 // The first two instructions are generated with labels so as to get the
4574 // offset fixed up correctly by the bind(Label*) call. We patch it back and
4575 // forth between a compare instructions (a nop in this position) and the
4576 // real branch when we start and stop incremental heap marking.
4577 __ jmp(&skip_to_incremental_noncompacting, Label::kNear);
4578 __ jmp(&skip_to_incremental_compacting, Label::kFar);
4579
4580 if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
4581 __ RememberedSetHelper(object_,
4582 address_,
4583 value_,
4584 save_fp_regs_mode_,
4585 MacroAssembler::kReturnAtEnd);
4586 } else {
4587 __ ret(0);
4588 }
4589
4590 __ bind(&skip_to_incremental_noncompacting);
4591 GenerateIncremental(masm, INCREMENTAL);
4592
4593 __ bind(&skip_to_incremental_compacting);
4594 GenerateIncremental(masm, INCREMENTAL_COMPACTION);
4595
4596 // Initial mode of the stub is expected to be STORE_BUFFER_ONLY.
4597 // Will be checked in IncrementalMarking::ActivateGeneratedStub.
4598 masm->set_byte_at(0, kTwoByteNopInstruction);
4599 masm->set_byte_at(2, kFiveByteNopInstruction);
4600}
4601
4602
4603void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
4604 regs_.Save(masm);
4605
4606 if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
4607 Label dont_need_remembered_set;
4608
4609 __ mov(regs_.scratch0(), Operand(regs_.address(), 0));
4610 __ JumpIfNotInNewSpace(regs_.scratch0(), // Value.
4611 regs_.scratch0(),
4612 &dont_need_remembered_set);
4613
4614 __ CheckPageFlag(regs_.object(),
4615 regs_.scratch0(),
4616 1 << MemoryChunk::SCAN_ON_SCAVENGE,
4617 not_zero,
4618 &dont_need_remembered_set);
4619
4620 // First notify the incremental marker if necessary, then update the
4621 // remembered set.
4622 CheckNeedsToInformIncrementalMarker(
4623 masm,
4624 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker,
4625 mode);
4626 InformIncrementalMarker(masm, mode);
4627 regs_.Restore(masm);
4628 __ RememberedSetHelper(object_,
4629 address_,
4630 value_,
4631 save_fp_regs_mode_,
4632 MacroAssembler::kReturnAtEnd);
4633
4634 __ bind(&dont_need_remembered_set);
4635 }
4636
4637 CheckNeedsToInformIncrementalMarker(
4638 masm,
4639 kReturnOnNoNeedToInformIncrementalMarker,
4640 mode);
4641 InformIncrementalMarker(masm, mode);
4642 regs_.Restore(masm);
4643 __ ret(0);
4644}
4645
4646
4647void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) {
4648 regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_);
4649 int argument_count = 3;
4650 __ PrepareCallCFunction(argument_count, regs_.scratch0());
4651 __ mov(Operand(esp, 0 * kPointerSize), regs_.object());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004652 __ mov(Operand(esp, 1 * kPointerSize), regs_.address()); // Slot.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004653 __ mov(Operand(esp, 2 * kPointerSize),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004654 Immediate(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004655
4656 AllowExternalCallThatCantCauseGC scope(masm);
4657 if (mode == INCREMENTAL_COMPACTION) {
4658 __ CallCFunction(
4659 ExternalReference::incremental_evacuation_record_write_function(
4660 masm->isolate()),
4661 argument_count);
4662 } else {
4663 ASSERT(mode == INCREMENTAL);
4664 __ CallCFunction(
4665 ExternalReference::incremental_marking_record_write_function(
4666 masm->isolate()),
4667 argument_count);
4668 }
4669 regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode_);
4670}
4671
4672
4673void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
4674 MacroAssembler* masm,
4675 OnNoNeedToInformIncrementalMarker on_no_need,
4676 Mode mode) {
4677 Label object_is_black, need_incremental, need_incremental_pop_object;
4678
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004679 __ mov(regs_.scratch0(), Immediate(~Page::kPageAlignmentMask));
4680 __ and_(regs_.scratch0(), regs_.object());
4681 __ mov(regs_.scratch1(),
4682 Operand(regs_.scratch0(),
4683 MemoryChunk::kWriteBarrierCounterOffset));
4684 __ sub(regs_.scratch1(), Immediate(1));
4685 __ mov(Operand(regs_.scratch0(),
4686 MemoryChunk::kWriteBarrierCounterOffset),
4687 regs_.scratch1());
4688 __ j(negative, &need_incremental);
4689
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004690 // Let's look at the color of the object: If it is not black we don't have
4691 // to inform the incremental marker.
4692 __ JumpIfBlack(regs_.object(),
4693 regs_.scratch0(),
4694 regs_.scratch1(),
4695 &object_is_black,
4696 Label::kNear);
4697
4698 regs_.Restore(masm);
4699 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
4700 __ RememberedSetHelper(object_,
4701 address_,
4702 value_,
4703 save_fp_regs_mode_,
4704 MacroAssembler::kReturnAtEnd);
4705 } else {
4706 __ ret(0);
4707 }
4708
4709 __ bind(&object_is_black);
4710
4711 // Get the value from the slot.
4712 __ mov(regs_.scratch0(), Operand(regs_.address(), 0));
4713
4714 if (mode == INCREMENTAL_COMPACTION) {
4715 Label ensure_not_white;
4716
4717 __ CheckPageFlag(regs_.scratch0(), // Contains value.
4718 regs_.scratch1(), // Scratch.
4719 MemoryChunk::kEvacuationCandidateMask,
4720 zero,
4721 &ensure_not_white,
4722 Label::kNear);
4723
4724 __ CheckPageFlag(regs_.object(),
4725 regs_.scratch1(), // Scratch.
4726 MemoryChunk::kSkipEvacuationSlotsRecordingMask,
4727 not_zero,
4728 &ensure_not_white,
4729 Label::kNear);
4730
4731 __ jmp(&need_incremental);
4732
4733 __ bind(&ensure_not_white);
4734 }
4735
4736 // We need an extra register for this, so we push the object register
4737 // temporarily.
4738 __ push(regs_.object());
4739 __ EnsureNotWhite(regs_.scratch0(), // The value.
4740 regs_.scratch1(), // Scratch.
4741 regs_.object(), // Scratch.
4742 &need_incremental_pop_object,
4743 Label::kNear);
4744 __ pop(regs_.object());
4745
4746 regs_.Restore(masm);
4747 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
4748 __ RememberedSetHelper(object_,
4749 address_,
4750 value_,
4751 save_fp_regs_mode_,
4752 MacroAssembler::kReturnAtEnd);
4753 } else {
4754 __ ret(0);
4755 }
4756
4757 __ bind(&need_incremental_pop_object);
4758 __ pop(regs_.object());
4759
4760 __ bind(&need_incremental);
4761
4762 // Fall through when we need to inform the incremental marker.
4763}
4764
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004765
4766void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
4767 // ----------- S t a t e -------------
4768 // -- eax : element value to store
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004769 // -- ecx : element index as smi
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004770 // -- esp[0] : return address
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00004771 // -- esp[4] : array literal index in function
4772 // -- esp[8] : array literal
4773 // clobbers ebx, edx, edi
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004774 // -----------------------------------
4775
4776 Label element_done;
4777 Label double_elements;
4778 Label smi_element;
4779 Label slow_elements;
4780 Label slow_elements_from_double;
4781 Label fast_elements;
4782
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00004783 // Get array literal index, array literal and its map.
4784 __ mov(edx, Operand(esp, 1 * kPointerSize));
4785 __ mov(ebx, Operand(esp, 2 * kPointerSize));
4786 __ mov(edi, FieldOperand(ebx, JSObject::kMapOffset));
4787
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004788 __ CheckFastElements(edi, &double_elements);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004789
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004790 // Check for FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS elements
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004791 __ JumpIfSmi(eax, &smi_element);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004792 __ CheckFastSmiElements(edi, &fast_elements, Label::kNear);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004793
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004794 // Store into the array literal requires a elements transition. Call into
4795 // the runtime.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004796
4797 __ bind(&slow_elements);
4798 __ pop(edi); // Pop return address and remember to put back later for tail
4799 // call.
4800 __ push(ebx);
4801 __ push(ecx);
4802 __ push(eax);
4803 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4804 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
4805 __ push(edx);
4806 __ push(edi); // Return return address so that tail call returns to right
4807 // place.
4808 __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
4809
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004810 __ bind(&slow_elements_from_double);
4811 __ pop(edx);
4812 __ jmp(&slow_elements);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004813
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004814 // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004815 __ bind(&fast_elements);
4816 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
4817 __ lea(ecx, FieldOperand(ebx, ecx, times_half_pointer_size,
4818 FixedArrayBase::kHeaderSize));
4819 __ mov(Operand(ecx, 0), eax);
4820 // Update the write barrier for the array store.
4821 __ RecordWrite(ebx, ecx, eax,
4822 kDontSaveFPRegs,
4823 EMIT_REMEMBERED_SET,
4824 OMIT_SMI_CHECK);
4825 __ ret(0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004826
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004827 // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS,
4828 // and value is Smi.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004829 __ bind(&smi_element);
4830 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
4831 __ mov(FieldOperand(ebx, ecx, times_half_pointer_size,
4832 FixedArrayBase::kHeaderSize), eax);
4833 __ ret(0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004834
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004835 // Array literal has ElementsKind of FAST_*_DOUBLE_ELEMENTS.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004836 __ bind(&double_elements);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004837
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00004838 __ push(edx);
4839 __ mov(edx, FieldOperand(ebx, JSObject::kElementsOffset));
4840 __ StoreNumberToDoubleElements(eax,
4841 edx,
4842 ecx,
4843 edi,
4844 xmm0,
4845 &slow_elements_from_double,
4846 false);
4847 __ pop(edx);
4848 __ ret(0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004849}
4850
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004851
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00004852void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004853 CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004854 __ call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00004855 int parameter_count_offset =
4856 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
4857 __ mov(ebx, MemOperand(ebp, parameter_count_offset));
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00004858 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00004859 __ pop(ecx);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00004860 int additional_offset = function_mode_ == JS_FUNCTION_STUB_MODE
4861 ? kPointerSize
4862 : 0;
4863 __ lea(esp, MemOperand(esp, ebx, times_pointer_size, additional_offset));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00004864 __ jmp(ecx); // Return to IC Miss stub, continuation still on stack.
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00004865}
4866
4867
machenbach@chromium.orgea468882013-11-18 08:53:19 +00004868void StubFailureTailCallTrampolineStub::Generate(MacroAssembler* masm) {
4869 CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
4870 __ call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
4871 __ mov(edi, eax);
4872 int parameter_count_offset =
4873 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
4874 __ mov(eax, MemOperand(ebp, parameter_count_offset));
4875 // The parameter count above includes the receiver for the arguments passed to
4876 // the deoptimization handler. Subtract the receiver for the parameter count
4877 // for the call.
4878 __ sub(eax, Immediate(1));
4879 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
4880 ParameterCount argument_count(eax);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00004881 __ InvokeFunction(edi, argument_count, JUMP_FUNCTION, NullCallWrapper());
machenbach@chromium.orgea468882013-11-18 08:53:19 +00004882}
4883
4884
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004885void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004886 if (masm->isolate()->function_entry_hook() != NULL) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004887 ProfileEntryHookStub stub;
4888 masm->CallStub(&stub);
4889 }
4890}
4891
4892
4893void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004894 // Save volatile registers.
4895 const int kNumSavedRegisters = 3;
4896 __ push(eax);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004897 __ push(ecx);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004898 __ push(edx);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004899
4900 // Calculate and push the original stack pointer.
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00004901 __ lea(eax, Operand(esp, (kNumSavedRegisters + 1) * kPointerSize));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004902 __ push(eax);
4903
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00004904 // Retrieve our return address and use it to calculate the calling
4905 // function's address.
4906 __ mov(eax, Operand(esp, (kNumSavedRegisters + 1) * kPointerSize));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004907 __ sub(eax, Immediate(Assembler::kCallInstructionLength));
4908 __ push(eax);
4909
4910 // Call the entry hook.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004911 ASSERT(masm->isolate()->function_entry_hook() != NULL);
4912 __ call(FUNCTION_ADDR(masm->isolate()->function_entry_hook()),
4913 RelocInfo::RUNTIME_ENTRY);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004914 __ add(esp, Immediate(2 * kPointerSize));
4915
4916 // Restore ecx.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004917 __ pop(edx);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004918 __ pop(ecx);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004919 __ pop(eax);
4920
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004921 __ ret(0);
4922}
4923
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004924
4925template<class T>
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004926static void CreateArrayDispatch(MacroAssembler* masm,
4927 AllocationSiteOverrideMode mode) {
4928 if (mode == DISABLE_ALLOCATION_SITES) {
4929 T stub(GetInitialFastElementsKind(),
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004930 mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004931 __ TailCallStub(&stub);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004932 } else if (mode == DONT_OVERRIDE) {
4933 int last_index = GetSequenceIndexFromFastElementsKind(
4934 TERMINAL_FAST_ELEMENTS_KIND);
4935 for (int i = 0; i <= last_index; ++i) {
4936 Label next;
4937 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
4938 __ cmp(edx, kind);
4939 __ j(not_equal, &next);
4940 T stub(kind);
4941 __ TailCallStub(&stub);
4942 __ bind(&next);
4943 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004944
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004945 // If we reached this point there is a problem.
4946 __ Abort(kUnexpectedElementsKindInArrayConstructor);
4947 } else {
4948 UNREACHABLE();
4949 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004950}
4951
4952
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004953static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
4954 AllocationSiteOverrideMode mode) {
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00004955 // ebx - allocation site (if mode != DISABLE_ALLOCATION_SITES)
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004956 // edx - kind (if mode != DISABLE_ALLOCATION_SITES)
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004957 // eax - number of arguments
4958 // edi - constructor?
4959 // esp[0] - return address
4960 // esp[4] - last argument
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004961 Label normal_sequence;
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004962 if (mode == DONT_OVERRIDE) {
4963 ASSERT(FAST_SMI_ELEMENTS == 0);
4964 ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
4965 ASSERT(FAST_ELEMENTS == 2);
4966 ASSERT(FAST_HOLEY_ELEMENTS == 3);
4967 ASSERT(FAST_DOUBLE_ELEMENTS == 4);
4968 ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
4969
4970 // is the low bit set? If so, we are holey and that is good.
4971 __ test_b(edx, 1);
4972 __ j(not_zero, &normal_sequence);
4973 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004974
4975 // look at the first argument
4976 __ mov(ecx, Operand(esp, kPointerSize));
4977 __ test(ecx, ecx);
4978 __ j(zero, &normal_sequence);
4979
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004980 if (mode == DISABLE_ALLOCATION_SITES) {
4981 ElementsKind initial = GetInitialFastElementsKind();
4982 ElementsKind holey_initial = GetHoleyElementsKind(initial);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004983
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004984 ArraySingleArgumentConstructorStub stub_holey(holey_initial,
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004985 DISABLE_ALLOCATION_SITES);
4986 __ TailCallStub(&stub_holey);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004987
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004988 __ bind(&normal_sequence);
4989 ArraySingleArgumentConstructorStub stub(initial,
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004990 DISABLE_ALLOCATION_SITES);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004991 __ TailCallStub(&stub);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004992 } else if (mode == DONT_OVERRIDE) {
4993 // We are going to create a holey array, but our kind is non-holey.
4994 // Fix kind and retry.
4995 __ inc(edx);
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00004996
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004997 if (FLAG_debug_code) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004998 Handle<Map> allocation_site_map =
4999 masm->isolate()->factory()->allocation_site_map();
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00005000 __ cmp(FieldOperand(ebx, 0), Immediate(allocation_site_map));
5001 __ Assert(equal, kExpectedAllocationSite);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005002 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005003
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00005004 // Save the resulting elements kind in type info. We can't just store r3
5005 // in the AllocationSite::transition_info field because elements kind is
5006 // restricted to a portion of the field...upper bits need to be left alone.
5007 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00005008 __ add(FieldOperand(ebx, AllocationSite::kTransitionInfoOffset),
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00005009 Immediate(Smi::FromInt(kFastElementsKindPackedToHoley)));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005010
5011 __ bind(&normal_sequence);
5012 int last_index = GetSequenceIndexFromFastElementsKind(
5013 TERMINAL_FAST_ELEMENTS_KIND);
5014 for (int i = 0; i <= last_index; ++i) {
5015 Label next;
5016 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
5017 __ cmp(edx, kind);
5018 __ j(not_equal, &next);
5019 ArraySingleArgumentConstructorStub stub(kind);
5020 __ TailCallStub(&stub);
5021 __ bind(&next);
5022 }
5023
5024 // If we reached this point there is a problem.
5025 __ Abort(kUnexpectedElementsKindInArrayConstructor);
5026 } else {
5027 UNREACHABLE();
5028 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005029}
5030
5031
5032template<class T>
5033static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
5034 int to_index = GetSequenceIndexFromFastElementsKind(
5035 TERMINAL_FAST_ELEMENTS_KIND);
5036 for (int i = 0; i <= to_index; ++i) {
5037 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005038 T stub(kind);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00005039 stub.GetCode(isolate);
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00005040 if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
machenbach@chromium.org03453962014-01-10 14:16:31 +00005041 T stub1(kind, DISABLE_ALLOCATION_SITES);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00005042 stub1.GetCode(isolate);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005043 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005044 }
5045}
5046
5047
5048void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) {
5049 ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>(
5050 isolate);
5051 ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>(
5052 isolate);
5053 ArrayConstructorStubAheadOfTimeHelper<ArrayNArgumentsConstructorStub>(
5054 isolate);
5055}
5056
5057
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005058void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(
5059 Isolate* isolate) {
5060 ElementsKind kinds[2] = { FAST_ELEMENTS, FAST_HOLEY_ELEMENTS };
5061 for (int i = 0; i < 2; i++) {
5062 // For internal arrays we only need a few things
5063 InternalArrayNoArgumentConstructorStub stubh1(kinds[i]);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00005064 stubh1.GetCode(isolate);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005065 InternalArraySingleArgumentConstructorStub stubh2(kinds[i]);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00005066 stubh2.GetCode(isolate);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005067 InternalArrayNArgumentsConstructorStub stubh3(kinds[i]);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00005068 stubh3.GetCode(isolate);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005069 }
5070}
5071
5072
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005073void ArrayConstructorStub::GenerateDispatchToArrayStub(
5074 MacroAssembler* masm,
5075 AllocationSiteOverrideMode mode) {
5076 if (argument_count_ == ANY) {
5077 Label not_zero_case, not_one_case;
5078 __ test(eax, eax);
5079 __ j(not_zero, &not_zero_case);
5080 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
5081
5082 __ bind(&not_zero_case);
5083 __ cmp(eax, 1);
5084 __ j(greater, &not_one_case);
5085 CreateArrayDispatchOneArgument(masm, mode);
5086
5087 __ bind(&not_one_case);
5088 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
5089 } else if (argument_count_ == NONE) {
5090 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
5091 } else if (argument_count_ == ONE) {
5092 CreateArrayDispatchOneArgument(masm, mode);
5093 } else if (argument_count_ == MORE_THAN_ONE) {
5094 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
5095 } else {
5096 UNREACHABLE();
5097 }
5098}
5099
5100
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005101void ArrayConstructorStub::Generate(MacroAssembler* masm) {
5102 // ----------- S t a t e -------------
5103 // -- eax : argc (only if argument_count_ == ANY)
5104 // -- ebx : type info cell
5105 // -- edi : constructor
5106 // -- esp[0] : return address
5107 // -- esp[4] : last argument
5108 // -----------------------------------
5109 Handle<Object> undefined_sentinel(
5110 masm->isolate()->heap()->undefined_value(),
5111 masm->isolate());
5112
5113 if (FLAG_debug_code) {
5114 // The array construct code is only set for the global and natives
5115 // builtin Array functions which always have maps.
5116
5117 // Initial map for the builtin Array function should be a map.
5118 __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
5119 // Will both indicate a NULL and a Smi.
5120 __ test(ecx, Immediate(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +00005121 __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005122 __ CmpObjectType(ecx, MAP_TYPE, ecx);
danno@chromium.org59400602013-08-13 17:09:37 +00005123 __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005124
danno@chromium.org41728482013-06-12 22:31:22 +00005125 // We should either have undefined in ebx or a valid cell
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005126 Label okay_here;
danno@chromium.org41728482013-06-12 22:31:22 +00005127 Handle<Map> cell_map = masm->isolate()->factory()->cell_map();
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005128 __ cmp(ebx, Immediate(undefined_sentinel));
5129 __ j(equal, &okay_here);
danno@chromium.org41728482013-06-12 22:31:22 +00005130 __ cmp(FieldOperand(ebx, 0), Immediate(cell_map));
danno@chromium.org59400602013-08-13 17:09:37 +00005131 __ Assert(equal, kExpectedPropertyCellInRegisterEbx);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005132 __ bind(&okay_here);
5133 }
5134
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005135 Label no_info;
5136 // If the type cell is undefined, or contains anything other than an
5137 // AllocationSite, call an array constructor that doesn't use AllocationSites.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005138 __ cmp(ebx, Immediate(undefined_sentinel));
5139 __ j(equal, &no_info);
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00005140 __ mov(ebx, FieldOperand(ebx, Cell::kValueOffset));
5141 __ cmp(FieldOperand(ebx, 0), Immediate(
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005142 masm->isolate()->factory()->allocation_site_map()));
danno@chromium.orgbee51992013-07-10 14:57:15 +00005143 __ j(not_equal, &no_info);
5144
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00005145 // Only look at the lower 16 bits of the transition info.
machenbach@chromium.org6d26cbb2014-01-22 10:50:56 +00005146 __ mov(edx, FieldOperand(ebx, AllocationSite::kTransitionInfoOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005147 __ SmiUntag(edx);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00005148 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
5149 __ and_(edx, Immediate(AllocationSite::ElementsKindBits::kMask));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005150 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
5151
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005152 __ bind(&no_info);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005153 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00005154}
5155
5156
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005157void InternalArrayConstructorStub::GenerateCase(
5158 MacroAssembler* masm, ElementsKind kind) {
5159 Label not_zero_case, not_one_case;
5160 Label normal_sequence;
5161
5162 __ test(eax, eax);
5163 __ j(not_zero, &not_zero_case);
5164 InternalArrayNoArgumentConstructorStub stub0(kind);
5165 __ TailCallStub(&stub0);
5166
5167 __ bind(&not_zero_case);
5168 __ cmp(eax, 1);
5169 __ j(greater, &not_one_case);
5170
5171 if (IsFastPackedElementsKind(kind)) {
5172 // We might need to create a holey array
5173 // look at the first argument
5174 __ mov(ecx, Operand(esp, kPointerSize));
5175 __ test(ecx, ecx);
5176 __ j(zero, &normal_sequence);
5177
5178 InternalArraySingleArgumentConstructorStub
5179 stub1_holey(GetHoleyElementsKind(kind));
5180 __ TailCallStub(&stub1_holey);
5181 }
5182
5183 __ bind(&normal_sequence);
5184 InternalArraySingleArgumentConstructorStub stub1(kind);
5185 __ TailCallStub(&stub1);
5186
5187 __ bind(&not_one_case);
5188 InternalArrayNArgumentsConstructorStub stubN(kind);
5189 __ TailCallStub(&stubN);
5190}
5191
5192
5193void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
5194 // ----------- S t a t e -------------
5195 // -- eax : argc
5196 // -- ebx : type info cell
5197 // -- edi : constructor
5198 // -- esp[0] : return address
5199 // -- esp[4] : last argument
5200 // -----------------------------------
5201
5202 if (FLAG_debug_code) {
5203 // The array construct code is only set for the global and natives
5204 // builtin Array functions which always have maps.
5205
5206 // Initial map for the builtin Array function should be a map.
5207 __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
5208 // Will both indicate a NULL and a Smi.
5209 __ test(ecx, Immediate(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +00005210 __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005211 __ CmpObjectType(ecx, MAP_TYPE, ecx);
danno@chromium.org59400602013-08-13 17:09:37 +00005212 __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005213 }
5214
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005215 // Figure out the right elements kind
5216 __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005217
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005218 // Load the map's "bit field 2" into |result|. We only need the first byte,
5219 // but the following masking takes care of that anyway.
5220 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
5221 // Retrieve elements_kind from bit field 2.
5222 __ and_(ecx, Map::kElementsKindMask);
5223 __ shr(ecx, Map::kElementsKindShift);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005224
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005225 if (FLAG_debug_code) {
5226 Label done;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005227 __ cmp(ecx, Immediate(FAST_ELEMENTS));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005228 __ j(equal, &done);
5229 __ cmp(ecx, Immediate(FAST_HOLEY_ELEMENTS));
5230 __ Assert(equal,
danno@chromium.org59400602013-08-13 17:09:37 +00005231 kInvalidElementsKindForInternalArrayOrInternalPackedArray);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005232 __ bind(&done);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005233 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005234
5235 Label fast_elements_case;
5236 __ cmp(ecx, Immediate(FAST_ELEMENTS));
5237 __ j(equal, &fast_elements_case);
5238 GenerateCase(masm, FAST_HOLEY_ELEMENTS);
5239
5240 __ bind(&fast_elements_case);
5241 GenerateCase(masm, FAST_ELEMENTS);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00005242}
5243
5244
machenbach@chromium.orge014e5b2014-01-28 07:51:38 +00005245void CallApiFunctionStub::Generate(MacroAssembler* masm) {
5246 // ----------- S t a t e -------------
5247 // -- eax : callee
5248 // -- ebx : call_data
5249 // -- ecx : holder
5250 // -- edx : api_function_address
5251 // -- esi : context
5252 // --
5253 // -- esp[0] : return address
5254 // -- esp[4] : last argument
5255 // -- ...
5256 // -- esp[argc * 4] : first argument
5257 // -- esp[(argc + 1) * 4] : receiver
5258 // -----------------------------------
5259
5260 Register callee = eax;
5261 Register call_data = ebx;
5262 Register holder = ecx;
5263 Register api_function_address = edx;
5264 Register return_address = edi;
5265 Register context = esi;
5266
5267 int argc = ArgumentBits::decode(bit_field_);
5268 bool restore_context = RestoreContextBits::decode(bit_field_);
5269 bool call_data_undefined = CallDataUndefinedBits::decode(bit_field_);
5270
5271 typedef FunctionCallbackArguments FCA;
5272
5273 STATIC_ASSERT(FCA::kContextSaveIndex == 6);
5274 STATIC_ASSERT(FCA::kCalleeIndex == 5);
5275 STATIC_ASSERT(FCA::kDataIndex == 4);
5276 STATIC_ASSERT(FCA::kReturnValueOffset == 3);
5277 STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
5278 STATIC_ASSERT(FCA::kIsolateIndex == 1);
5279 STATIC_ASSERT(FCA::kHolderIndex == 0);
5280 STATIC_ASSERT(FCA::kArgsLength == 7);
5281
5282 Isolate* isolate = masm->isolate();
5283
5284 __ pop(return_address);
5285
5286 // context save
5287 __ push(context);
5288 // load context from callee
5289 __ mov(context, FieldOperand(callee, JSFunction::kContextOffset));
5290
5291 // callee
5292 __ push(callee);
5293
5294 // call data
5295 __ push(call_data);
5296
5297 Register scratch = call_data;
5298 if (!call_data_undefined) {
5299 // return value
5300 __ push(Immediate(isolate->factory()->undefined_value()));
5301 // return value default
5302 __ push(Immediate(isolate->factory()->undefined_value()));
5303 } else {
5304 // return value
5305 __ push(scratch);
5306 // return value default
5307 __ push(scratch);
5308 }
5309 // isolate
5310 __ push(Immediate(reinterpret_cast<int>(isolate)));
5311 // holder
5312 __ push(holder);
5313
5314 __ mov(scratch, esp);
5315
5316 // return address
5317 __ push(return_address);
5318
5319 // API function gets reference to the v8::Arguments. If CPU profiler
5320 // is enabled wrapper function will be called and we need to pass
5321 // address of the callback as additional parameter, always allocate
5322 // space for it.
5323 const int kApiArgc = 1 + 1;
5324
5325 // Allocate the v8::Arguments structure in the arguments' space since
5326 // it's not controlled by GC.
5327 const int kApiStackSpace = 4;
5328
5329 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace);
5330
5331 // FunctionCallbackInfo::implicit_args_.
5332 __ mov(ApiParameterOperand(2), scratch);
5333 __ add(scratch, Immediate((argc + FCA::kArgsLength - 1) * kPointerSize));
5334 // FunctionCallbackInfo::values_.
5335 __ mov(ApiParameterOperand(3), scratch);
5336 // FunctionCallbackInfo::length_.
5337 __ Set(ApiParameterOperand(4), Immediate(argc));
5338 // FunctionCallbackInfo::is_construct_call_.
5339 __ Set(ApiParameterOperand(5), Immediate(0));
5340
5341 // v8::InvocationCallback's argument.
5342 __ lea(scratch, ApiParameterOperand(2));
5343 __ mov(ApiParameterOperand(0), scratch);
5344
5345 Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback);
5346
5347 Operand context_restore_operand(ebp,
5348 (2 + FCA::kContextSaveIndex) * kPointerSize);
5349 Operand return_value_operand(ebp,
5350 (2 + FCA::kReturnValueOffset) * kPointerSize);
5351 __ CallApiFunctionAndReturn(api_function_address,
5352 thunk_address,
5353 ApiParameterOperand(1),
5354 argc + FCA::kArgsLength + 1,
5355 return_value_operand,
5356 restore_context ?
5357 &context_restore_operand : NULL);
5358}
5359
5360
ricow@chromium.org65fae842010-08-25 15:26:24 +00005361#undef __
5362
5363} } // namespace v8::internal
5364
5365#endif // V8_TARGET_ARCH_IA32