blob: ae3adb7b6f4c2e2a24746771e84178762a405b6f [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Blocka7e24c12009-10-30 11:49:00 +00004
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005#include "src/code-stubs.h"
6
7#include <sstream>
Steve Blocka7e24c12009-10-30 11:49:00 +00008
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#include "src/bootstrapper.h"
Ben Murdochda12d292016-06-02 14:46:10 +010010#include "src/code-factory.h"
Ben Murdochc5610432016-08-08 18:44:38 +010011#include "src/code-stub-assembler.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012#include "src/factory.h"
13#include "src/gdb-jit.h"
14#include "src/ic/handler-compiler.h"
15#include "src/ic/ic.h"
16#include "src/macro-assembler.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017#include "src/parsing/parser.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000018
19namespace v8 {
20namespace internal {
21
Ben Murdochb8a8cc12014-11-26 15:28:44 +000022
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000023RUNTIME_FUNCTION(UnexpectedStubMiss) {
24 FATAL("Unexpected deopt of a stub");
25 return Smi::FromInt(0);
26}
27
28
Ben Murdochb8a8cc12014-11-26 15:28:44 +000029CodeStubDescriptor::CodeStubDescriptor(CodeStub* stub)
30 : call_descriptor_(stub->GetCallInterfaceDescriptor()),
31 stack_parameter_count_(no_reg),
32 hint_stack_parameter_count_(-1),
33 function_mode_(NOT_JS_FUNCTION_STUB_MODE),
34 deoptimization_handler_(NULL),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035 miss_handler_(),
36 has_miss_handler_(false) {
37 stub->InitializeDescriptor(this);
38}
39
40
41CodeStubDescriptor::CodeStubDescriptor(Isolate* isolate, uint32_t stub_key)
42 : stack_parameter_count_(no_reg),
43 hint_stack_parameter_count_(-1),
44 function_mode_(NOT_JS_FUNCTION_STUB_MODE),
45 deoptimization_handler_(NULL),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000046 miss_handler_(),
47 has_miss_handler_(false) {
48 CodeStub::InitializeDescriptor(isolate, stub_key, this);
49}
50
51
52void CodeStubDescriptor::Initialize(Address deoptimization_handler,
53 int hint_stack_parameter_count,
54 StubFunctionMode function_mode) {
55 deoptimization_handler_ = deoptimization_handler;
56 hint_stack_parameter_count_ = hint_stack_parameter_count;
57 function_mode_ = function_mode;
58}
59
60
61void CodeStubDescriptor::Initialize(Register stack_parameter_count,
62 Address deoptimization_handler,
63 int hint_stack_parameter_count,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000064 StubFunctionMode function_mode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000065 Initialize(deoptimization_handler, hint_stack_parameter_count, function_mode);
66 stack_parameter_count_ = stack_parameter_count;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000067}
68
69
Leon Clarkee46be812010-01-19 14:06:41 +000070bool CodeStub::FindCodeInCache(Code** code_out) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000071 UnseededNumberDictionary* stubs = isolate()->heap()->code_stubs();
72 int index = stubs->FindEntry(GetKey());
Ben Murdochc7cc0282012-03-05 14:35:55 +000073 if (index != UnseededNumberDictionary::kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000074 *code_out = Code::cast(stubs->ValueAt(index));
Leon Clarkee46be812010-01-19 14:06:41 +000075 return true;
Steve Blockd0582a62009-12-15 09:54:21 +000076 }
Leon Clarkee46be812010-01-19 14:06:41 +000077 return false;
78}
Steve Blockd0582a62009-12-15 09:54:21 +000079
Leon Clarkee46be812010-01-19 14:06:41 +000080
Ben Murdochb8a8cc12014-11-26 15:28:44 +000081void CodeStub::RecordCodeGeneration(Handle<Code> code) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040082 std::ostringstream os;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000083 os << *this;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040084 PROFILE(isolate(),
Ben Murdoch61f157c2016-09-16 13:49:30 +010085 CodeCreateEvent(CodeEventListener::STUB_TAG,
86 AbstractCode::cast(*code), os.str().c_str()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000087 Counters* counters = isolate()->counters();
Steve Block44f0eee2011-05-26 01:26:41 +010088 counters->total_stubs_code_size()->Increment(code->instruction_size());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000089#ifdef DEBUG
90 code->VerifyEmbeddedObjects();
91#endif
Leon Clarkee46be812010-01-19 14:06:41 +000092}
93
94
Ben Murdochb8a8cc12014-11-26 15:28:44 +000095Code::Kind CodeStub::GetCodeKind() const {
Steve Block6ded16b2010-05-10 14:33:55 +010096 return Code::STUB;
97}
98
99
Ben Murdoch097c5b22016-05-18 11:27:45 +0100100Code::Flags CodeStub::GetCodeFlags() const {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100101 return Code::ComputeFlags(GetCodeKind(), GetExtraICState());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100102}
103
104
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000105Handle<Code> CodeStub::GetCodeCopy(const Code::FindAndReplacePattern& pattern) {
106 Handle<Code> ic = GetCode();
107 ic = isolate()->factory()->CopyCode(ic);
108 ic->FindAndReplace(pattern);
109 RecordCodeGeneration(ic);
110 return ic;
111}
112
113
114Handle<Code> PlatformCodeStub::GenerateCode() {
115 Factory* factory = isolate()->factory();
116
117 // Generate the new code.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000118 MacroAssembler masm(isolate(), NULL, 256, CodeObjectRequired::kYes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000119
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000120 {
121 // Update the static counter each time a new code stub is generated.
122 isolate()->counters()->code_stubs()->Increment();
123
124 // Generate the code for the stub.
125 masm.set_generating_stub(true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400126 // TODO(yangguo): remove this once we can serialize IC stubs.
127 masm.enable_serializer();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000128 NoCurrentFrameScope scope(&masm);
129 Generate(&masm);
130 }
131
132 // Create the code object.
133 CodeDesc desc;
134 masm.GetCode(&desc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000135 // Copy the generated code into a heap object.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100136 Code::Flags flags = Code::ComputeFlags(GetCodeKind(), GetExtraICState());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000137 Handle<Code> new_object = factory->NewCode(
138 desc, flags, masm.CodeObject(), NeedsImmovableCode());
139 return new_object;
140}
141
142
Leon Clarkee46be812010-01-19 14:06:41 +0000143Handle<Code> CodeStub::GetCode() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000144 Heap* heap = isolate()->heap();
Leon Clarkee46be812010-01-19 14:06:41 +0000145 Code* code;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000146 if (UseSpecialCache() ? FindCodeInSpecialCache(&code)
147 : FindCodeInCache(&code)) {
148 DCHECK(GetCodeKind() == code->kind());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100149 return Handle<Code>(code);
150 }
151
152 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000153 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000154
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000155 Handle<Code> new_object = GenerateCode();
156 new_object->set_stub_key(GetKey());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100157 FinishCode(new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000158 RecordCodeGeneration(new_object);
159
160#ifdef ENABLE_DISASSEMBLER
161 if (FLAG_print_code_stubs) {
162 CodeTracer::Scope trace_scope(isolate()->GetCodeTracer());
163 OFStream os(trace_scope.file());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400164 std::ostringstream name;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000165 name << *this;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400166 new_object->Disassemble(name.str().c_str(), os);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000167 os << "\n";
168 }
169#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000170
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100171 if (UseSpecialCache()) {
172 AddToSpecialCache(new_object);
173 } else {
174 // Update the dictionary and the root in Heap.
175 Handle<UnseededNumberDictionary> dict =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000176 UnseededNumberDictionary::AtNumberPut(
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100177 Handle<UnseededNumberDictionary>(heap->code_stubs()),
178 GetKey(),
179 new_object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000180 heap->SetRootCodeStubs(*dict);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100181 }
Leon Clarkee46be812010-01-19 14:06:41 +0000182 code = *new_object;
Steve Blocka7e24c12009-10-30 11:49:00 +0000183 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000184
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100185 Activate(code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000186 DCHECK(!NeedsImmovableCode() ||
187 heap->lo_space()->Contains(code) ||
188 heap->code_space()->FirstPage()->Contains(code->address()));
189 return Handle<Code>(code, isolate());
Leon Clarkee46be812010-01-19 14:06:41 +0000190}
191
192
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000193const char* CodeStub::MajorName(CodeStub::Major major_key) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000194 switch (major_key) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000195#define DEF_CASE(name) case name: return #name "Stub";
Steve Blockd0582a62009-12-15 09:54:21 +0000196 CODE_STUB_LIST(DEF_CASE)
197#undef DEF_CASE
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000198 case NoCache:
199 return "<NoCache>Stub";
200 case NUMBER_OF_IDS:
201 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +0000202 return NULL;
203 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000204 return NULL;
205}
206
207
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400208void CodeStub::PrintBaseName(std::ostream& os) const { // NOLINT
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000209 os << MajorName(MajorKey());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000210}
211
212
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400213void CodeStub::PrintName(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000214 PrintBaseName(os);
215 PrintState(os);
216}
217
218
219void CodeStub::Dispatch(Isolate* isolate, uint32_t key, void** value_out,
220 DispatchedCall call) {
221 switch (MajorKeyFromKey(key)) {
222#define DEF_CASE(NAME) \
223 case NAME: { \
224 NAME##Stub stub(key, isolate); \
225 CodeStub* pstub = &stub; \
226 call(pstub, value_out); \
227 break; \
228 }
229 CODE_STUB_LIST(DEF_CASE)
230#undef DEF_CASE
231 case NUMBER_OF_IDS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000232 case NoCache:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400233 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000234 break;
235 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000236}
237
238
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000239static void InitializeDescriptorDispatchedCall(CodeStub* stub,
240 void** value_out) {
241 CodeStubDescriptor* descriptor_out =
242 reinterpret_cast<CodeStubDescriptor*>(value_out);
243 stub->InitializeDescriptor(descriptor_out);
244 descriptor_out->set_call_descriptor(stub->GetCallInterfaceDescriptor());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100245}
246
247
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000248void CodeStub::InitializeDescriptor(Isolate* isolate, uint32_t key,
249 CodeStubDescriptor* desc) {
250 void** value_out = reinterpret_cast<void**>(desc);
251 Dispatch(isolate, key, value_out, &InitializeDescriptorDispatchedCall);
252}
253
254
255void CodeStub::GetCodeDispatchCall(CodeStub* stub, void** value_out) {
256 Handle<Code>* code_out = reinterpret_cast<Handle<Code>*>(value_out);
257 // Code stubs with special cache cannot be recreated from stub key.
258 *code_out = stub->UseSpecialCache() ? Handle<Code>() : stub->GetCode();
259}
260
261
262MaybeHandle<Code> CodeStub::GetCode(Isolate* isolate, uint32_t key) {
263 HandleScope scope(isolate);
264 Handle<Code> code;
265 void** value_out = reinterpret_cast<void**>(&code);
266 Dispatch(isolate, key, value_out, &GetCodeDispatchCall);
267 return scope.CloseAndEscape(code);
268}
269
270
271// static
272void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate) {
273 // Generate the uninitialized versions of the stub.
274 for (int op = Token::BIT_OR; op <= Token::MOD; ++op) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100275 BinaryOpICStub stub(isolate, static_cast<Token::Value>(op));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000276 stub.GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000277 }
278
279 // Generate special versions of the stub.
280 BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
281}
282
283
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400284void BinaryOpICStub::PrintState(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000285 os << state();
286}
287
288
289// static
290void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate,
291 const BinaryOpICState& state) {
292 BinaryOpICStub stub(isolate, state);
293 stub.GetCode();
294}
295
296
297// static
298void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
299 // Generate special versions of the stub.
300 BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
301}
302
303
304void BinaryOpICWithAllocationSiteStub::PrintState(
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400305 std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000306 os << state();
307}
308
309
310// static
311void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(
312 Isolate* isolate, const BinaryOpICState& state) {
313 if (state.CouldCreateAllocationMementos()) {
314 BinaryOpICWithAllocationSiteStub stub(isolate, state);
315 stub.GetCode();
316 }
317}
318
319
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000320std::ostream& operator<<(std::ostream& os, const StringAddFlags& flags) {
321 switch (flags) {
322 case STRING_ADD_CHECK_NONE:
323 return os << "CheckNone";
324 case STRING_ADD_CHECK_LEFT:
325 return os << "CheckLeft";
326 case STRING_ADD_CHECK_RIGHT:
327 return os << "CheckRight";
328 case STRING_ADD_CHECK_BOTH:
329 return os << "CheckBoth";
330 case STRING_ADD_CONVERT_LEFT:
331 return os << "ConvertLeft";
332 case STRING_ADD_CONVERT_RIGHT:
333 return os << "ConvertRight";
334 case STRING_ADD_CONVERT:
335 break;
336 }
337 UNREACHABLE();
338 return os;
339}
340
341
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400342void StringAddStub::PrintBaseName(std::ostream& os) const { // NOLINT
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000343 os << "StringAddStub_" << flags() << "_" << pretenure_flag();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000344}
345
346
347InlineCacheState CompareICStub::GetICState() const {
348 CompareICState::State state = Max(left(), right());
349 switch (state) {
350 case CompareICState::UNINITIALIZED:
351 return ::v8::internal::UNINITIALIZED;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000352 case CompareICState::BOOLEAN:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000353 case CompareICState::SMI:
354 case CompareICState::NUMBER:
355 case CompareICState::INTERNALIZED_STRING:
356 case CompareICState::STRING:
357 case CompareICState::UNIQUE_NAME:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000358 case CompareICState::RECEIVER:
359 case CompareICState::KNOWN_RECEIVER:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000360 return MONOMORPHIC;
361 case CompareICState::GENERIC:
362 return ::v8::internal::GENERIC;
363 }
364 UNREACHABLE();
365 return ::v8::internal::UNINITIALIZED;
366}
367
368
369Condition CompareICStub::GetCondition() const {
370 return CompareIC::ComputeCondition(op());
371}
372
373
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000374void CompareICStub::Generate(MacroAssembler* masm) {
375 switch (state()) {
376 case CompareICState::UNINITIALIZED:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100377 GenerateMiss(masm);
378 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000379 case CompareICState::BOOLEAN:
380 GenerateBooleans(masm);
381 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000382 case CompareICState::SMI:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100383 GenerateSmis(masm);
384 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000385 case CompareICState::NUMBER:
386 GenerateNumbers(masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100387 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000388 case CompareICState::STRING:
Ben Murdoch257744e2011-11-30 15:57:28 +0000389 GenerateStrings(masm);
390 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000391 case CompareICState::INTERNALIZED_STRING:
392 GenerateInternalizedStrings(masm);
Ben Murdoch257744e2011-11-30 15:57:28 +0000393 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000394 case CompareICState::UNIQUE_NAME:
395 GenerateUniqueNames(masm);
396 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000397 case CompareICState::RECEIVER:
398 GenerateReceivers(masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100399 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000400 case CompareICState::KNOWN_RECEIVER:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000401 DCHECK(*known_map_ != NULL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000402 GenerateKnownReceivers(masm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100403 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000404 case CompareICState::GENERIC:
405 GenerateGeneric(masm);
406 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100407 }
408}
409
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000410Handle<Code> TurboFanCodeStub::GenerateCode() {
411 const char* name = CodeStub::MajorName(MajorKey());
Ben Murdochda12d292016-06-02 14:46:10 +0100412 Zone zone(isolate()->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000413 CallInterfaceDescriptor descriptor(GetCallInterfaceDescriptor());
Ben Murdochc5610432016-08-08 18:44:38 +0100414 CodeStubAssembler assembler(isolate(), &zone, descriptor, GetCodeFlags(),
415 name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000416 GenerateAssembly(&assembler);
417 return assembler.GenerateCode();
418}
419
Ben Murdoch61f157c2016-09-16 13:49:30 +0100420void LoadICTrampolineTFStub::GenerateAssembly(
421 CodeStubAssembler* assembler) const {
422 typedef compiler::Node Node;
423
424 Node* receiver = assembler->Parameter(0);
425 Node* name = assembler->Parameter(1);
426 Node* slot = assembler->Parameter(2);
427 Node* context = assembler->Parameter(3);
428 Node* vector = assembler->LoadTypeFeedbackVectorForStub();
429
430 CodeStubAssembler::LoadICParameters p(context, receiver, name, slot, vector);
431 assembler->LoadIC(&p);
432}
433
434void LoadICTFStub::GenerateAssembly(CodeStubAssembler* assembler) const {
435 typedef compiler::Node Node;
436
437 Node* receiver = assembler->Parameter(0);
438 Node* name = assembler->Parameter(1);
439 Node* slot = assembler->Parameter(2);
440 Node* vector = assembler->Parameter(3);
441 Node* context = assembler->Parameter(4);
442
443 CodeStubAssembler::LoadICParameters p(context, receiver, name, slot, vector);
444 assembler->LoadIC(&p);
445}
446
447void LoadGlobalICTrampolineStub::GenerateAssembly(
448 CodeStubAssembler* assembler) const {
449 typedef compiler::Node Node;
450
451 Node* slot = assembler->Parameter(0);
452 Node* context = assembler->Parameter(1);
453 Node* vector = assembler->LoadTypeFeedbackVectorForStub();
454
455 CodeStubAssembler::LoadICParameters p(context, nullptr, nullptr, slot,
456 vector);
457 assembler->LoadGlobalIC(&p);
458}
459
460void LoadGlobalICStub::GenerateAssembly(CodeStubAssembler* assembler) const {
461 typedef compiler::Node Node;
462
463 Node* slot = assembler->Parameter(0);
464 Node* vector = assembler->Parameter(1);
465 Node* context = assembler->Parameter(2);
466
467 CodeStubAssembler::LoadICParameters p(context, nullptr, nullptr, slot,
468 vector);
469 assembler->LoadGlobalIC(&p);
470}
471
Ben Murdochda12d292016-06-02 14:46:10 +0100472void AllocateHeapNumberStub::GenerateAssembly(
Ben Murdochc5610432016-08-08 18:44:38 +0100473 CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +0100474 typedef compiler::Node Node;
475
476 Node* result = assembler->AllocateHeapNumber();
477 assembler->Return(result);
478}
479
Ben Murdochda12d292016-06-02 14:46:10 +0100480#define SIMD128_GEN_ASM(TYPE, Type, type, lane_count, lane_type) \
Ben Murdochc5610432016-08-08 18:44:38 +0100481 void Allocate##Type##Stub::GenerateAssembly(CodeStubAssembler* assembler) \
482 const { \
483 compiler::Node* result = \
484 assembler->Allocate(Simd128Value::kSize, CodeStubAssembler::kNone); \
Ben Murdochda12d292016-06-02 14:46:10 +0100485 compiler::Node* map_offset = \
486 assembler->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag); \
487 compiler::Node* map = assembler->IntPtrAdd(result, map_offset); \
488 assembler->StoreNoWriteBarrier( \
489 MachineRepresentation::kTagged, map, \
490 assembler->HeapConstant(isolate()->factory()->type##_map())); \
491 assembler->Return(result); \
492 }
493SIMD128_TYPES(SIMD128_GEN_ASM)
494#undef SIMD128_GEN_ASM
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000495
Ben Murdochc5610432016-08-08 18:44:38 +0100496void StringLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000497 compiler::Node* value = assembler->Parameter(0);
498 compiler::Node* string =
499 assembler->LoadObjectField(value, JSValue::kValueOffset);
500 compiler::Node* result =
501 assembler->LoadObjectField(string, String::kLengthOffset);
502 assembler->Return(result);
503}
504
Ben Murdochc5610432016-08-08 18:44:38 +0100505// static
506compiler::Node* AddStub::Generate(CodeStubAssembler* assembler,
507 compiler::Node* left, compiler::Node* right,
508 compiler::Node* context) {
509 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +0100510 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +0100511 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +0100512
513 // Shared entry for floating point addition.
514 Label do_fadd(assembler);
515 Variable var_fadd_lhs(assembler, MachineRepresentation::kFloat64),
516 var_fadd_rhs(assembler, MachineRepresentation::kFloat64);
517
518 // We might need to loop several times due to ToPrimitive, ToString and/or
519 // ToNumber conversions.
520 Variable var_lhs(assembler, MachineRepresentation::kTagged),
Ben Murdochc5610432016-08-08 18:44:38 +0100521 var_rhs(assembler, MachineRepresentation::kTagged),
522 var_result(assembler, MachineRepresentation::kTagged);
Ben Murdochda12d292016-06-02 14:46:10 +0100523 Variable* loop_vars[2] = {&var_lhs, &var_rhs};
Ben Murdochc5610432016-08-08 18:44:38 +0100524 Label loop(assembler, 2, loop_vars), end(assembler),
525 string_add_convert_left(assembler, Label::kDeferred),
526 string_add_convert_right(assembler, Label::kDeferred);
527 var_lhs.Bind(left);
528 var_rhs.Bind(right);
Ben Murdochda12d292016-06-02 14:46:10 +0100529 assembler->Goto(&loop);
530 assembler->Bind(&loop);
531 {
532 // Load the current {lhs} and {rhs} values.
533 Node* lhs = var_lhs.value();
534 Node* rhs = var_rhs.value();
535
536 // Check if the {lhs} is a Smi or a HeapObject.
537 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
538 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
539
540 assembler->Bind(&if_lhsissmi);
541 {
542 // Check if the {rhs} is also a Smi.
543 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
544 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
545 &if_rhsisnotsmi);
546
547 assembler->Bind(&if_rhsissmi);
548 {
549 // Try fast Smi addition first.
550 Node* pair = assembler->SmiAddWithOverflow(lhs, rhs);
551 Node* overflow = assembler->Projection(1, pair);
552
553 // Check if the Smi additon overflowed.
554 Label if_overflow(assembler), if_notoverflow(assembler);
555 assembler->Branch(overflow, &if_overflow, &if_notoverflow);
556
557 assembler->Bind(&if_overflow);
558 {
559 var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs));
560 var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs));
561 assembler->Goto(&do_fadd);
562 }
563
564 assembler->Bind(&if_notoverflow);
Ben Murdochc5610432016-08-08 18:44:38 +0100565 var_result.Bind(assembler->Projection(0, pair));
566 assembler->Goto(&end);
Ben Murdochda12d292016-06-02 14:46:10 +0100567 }
568
569 assembler->Bind(&if_rhsisnotsmi);
570 {
571 // Load the map of {rhs}.
572 Node* rhs_map = assembler->LoadObjectField(rhs, HeapObject::kMapOffset);
573
574 // Check if the {rhs} is a HeapNumber.
575 Label if_rhsisnumber(assembler),
576 if_rhsisnotnumber(assembler, Label::kDeferred);
577 Node* number_map = assembler->HeapNumberMapConstant();
578 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
579 &if_rhsisnumber, &if_rhsisnotnumber);
580
581 assembler->Bind(&if_rhsisnumber);
582 {
583 var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs));
584 var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
585 assembler->Goto(&do_fadd);
586 }
587
588 assembler->Bind(&if_rhsisnotnumber);
589 {
590 // Load the instance type of {rhs}.
591 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
592
593 // Check if the {rhs} is a String.
594 Label if_rhsisstring(assembler, Label::kDeferred),
595 if_rhsisnotstring(assembler, Label::kDeferred);
596 assembler->Branch(assembler->Int32LessThan(
597 rhs_instance_type,
598 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
599 &if_rhsisstring, &if_rhsisnotstring);
600
601 assembler->Bind(&if_rhsisstring);
602 {
Ben Murdochc5610432016-08-08 18:44:38 +0100603 var_lhs.Bind(lhs);
604 var_rhs.Bind(rhs);
605 assembler->Goto(&string_add_convert_left);
Ben Murdochda12d292016-06-02 14:46:10 +0100606 }
607
608 assembler->Bind(&if_rhsisnotstring);
609 {
610 // Check if {rhs} is a JSReceiver.
611 Label if_rhsisreceiver(assembler, Label::kDeferred),
612 if_rhsisnotreceiver(assembler, Label::kDeferred);
613 assembler->Branch(
614 assembler->Int32LessThanOrEqual(
615 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
616 rhs_instance_type),
617 &if_rhsisreceiver, &if_rhsisnotreceiver);
618
619 assembler->Bind(&if_rhsisreceiver);
620 {
621 // Convert {rhs} to a primitive first passing no hint.
622 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
623 var_rhs.Bind(
624 assembler->CallRuntime(Runtime::kToPrimitive, context, rhs));
625 assembler->Goto(&loop);
626 }
627
628 assembler->Bind(&if_rhsisnotreceiver);
629 {
630 // Convert {rhs} to a Number first.
631 Callable callable =
632 CodeFactory::NonNumberToNumber(assembler->isolate());
633 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
634 assembler->Goto(&loop);
635 }
636 }
637 }
638 }
639 }
640
641 assembler->Bind(&if_lhsisnotsmi);
642 {
643 // Load the map and instance type of {lhs}.
644 Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
645
646 // Check if {lhs} is a String.
647 Label if_lhsisstring(assembler), if_lhsisnotstring(assembler);
648 assembler->Branch(assembler->Int32LessThan(
649 lhs_instance_type,
650 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
651 &if_lhsisstring, &if_lhsisnotstring);
652
653 assembler->Bind(&if_lhsisstring);
654 {
Ben Murdochc5610432016-08-08 18:44:38 +0100655 var_lhs.Bind(lhs);
656 var_rhs.Bind(rhs);
657 assembler->Goto(&string_add_convert_right);
Ben Murdochda12d292016-06-02 14:46:10 +0100658 }
659
660 assembler->Bind(&if_lhsisnotstring);
661 {
662 // Check if {rhs} is a Smi.
663 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
664 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
665 &if_rhsisnotsmi);
666
667 assembler->Bind(&if_rhsissmi);
668 {
669 // Check if {lhs} is a Number.
670 Label if_lhsisnumber(assembler),
671 if_lhsisnotnumber(assembler, Label::kDeferred);
672 assembler->Branch(assembler->Word32Equal(
673 lhs_instance_type,
674 assembler->Int32Constant(HEAP_NUMBER_TYPE)),
675 &if_lhsisnumber, &if_lhsisnotnumber);
676
677 assembler->Bind(&if_lhsisnumber);
678 {
679 // The {lhs} is a HeapNumber, the {rhs} is a Smi, just add them.
680 var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
681 var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs));
682 assembler->Goto(&do_fadd);
683 }
684
685 assembler->Bind(&if_lhsisnotnumber);
686 {
687 // The {lhs} is neither a Number nor a String, and the {rhs} is a
688 // Smi.
689 Label if_lhsisreceiver(assembler, Label::kDeferred),
690 if_lhsisnotreceiver(assembler, Label::kDeferred);
691 assembler->Branch(
692 assembler->Int32LessThanOrEqual(
693 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
694 lhs_instance_type),
695 &if_lhsisreceiver, &if_lhsisnotreceiver);
696
697 assembler->Bind(&if_lhsisreceiver);
698 {
699 // Convert {lhs} to a primitive first passing no hint.
700 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
701 var_lhs.Bind(
702 assembler->CallRuntime(Runtime::kToPrimitive, context, lhs));
703 assembler->Goto(&loop);
704 }
705
706 assembler->Bind(&if_lhsisnotreceiver);
707 {
708 // Convert {lhs} to a Number first.
709 Callable callable =
710 CodeFactory::NonNumberToNumber(assembler->isolate());
711 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
712 assembler->Goto(&loop);
713 }
714 }
715 }
716
717 assembler->Bind(&if_rhsisnotsmi);
718 {
719 // Load the instance type of {rhs}.
720 Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
721
722 // Check if {rhs} is a String.
723 Label if_rhsisstring(assembler), if_rhsisnotstring(assembler);
724 assembler->Branch(assembler->Int32LessThan(
725 rhs_instance_type,
726 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
727 &if_rhsisstring, &if_rhsisnotstring);
728
729 assembler->Bind(&if_rhsisstring);
730 {
Ben Murdochc5610432016-08-08 18:44:38 +0100731 var_lhs.Bind(lhs);
732 var_rhs.Bind(rhs);
733 assembler->Goto(&string_add_convert_left);
Ben Murdochda12d292016-06-02 14:46:10 +0100734 }
735
736 assembler->Bind(&if_rhsisnotstring);
737 {
738 // Check if {lhs} is a HeapNumber.
739 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler);
740 assembler->Branch(assembler->Word32Equal(
741 lhs_instance_type,
742 assembler->Int32Constant(HEAP_NUMBER_TYPE)),
743 &if_lhsisnumber, &if_lhsisnotnumber);
744
745 assembler->Bind(&if_lhsisnumber);
746 {
747 // Check if {rhs} is also a HeapNumber.
748 Label if_rhsisnumber(assembler),
749 if_rhsisnotnumber(assembler, Label::kDeferred);
750 assembler->Branch(assembler->Word32Equal(
751 rhs_instance_type,
752 assembler->Int32Constant(HEAP_NUMBER_TYPE)),
753 &if_rhsisnumber, &if_rhsisnotnumber);
754
755 assembler->Bind(&if_rhsisnumber);
756 {
757 // Perform a floating point addition.
758 var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
759 var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
760 assembler->Goto(&do_fadd);
761 }
762
763 assembler->Bind(&if_rhsisnotnumber);
764 {
765 // Check if {rhs} is a JSReceiver.
766 Label if_rhsisreceiver(assembler, Label::kDeferred),
767 if_rhsisnotreceiver(assembler, Label::kDeferred);
768 assembler->Branch(
769 assembler->Int32LessThanOrEqual(
770 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
771 rhs_instance_type),
772 &if_rhsisreceiver, &if_rhsisnotreceiver);
773
774 assembler->Bind(&if_rhsisreceiver);
775 {
776 // Convert {rhs} to a primitive first passing no hint.
777 // TODO(bmeurer): Hook up ToPrimitiveStub here too.
778 var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
779 context, rhs));
780 assembler->Goto(&loop);
781 }
782
783 assembler->Bind(&if_rhsisnotreceiver);
784 {
785 // Convert {rhs} to a Number first.
786 Callable callable =
787 CodeFactory::NonNumberToNumber(assembler->isolate());
788 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
789 assembler->Goto(&loop);
790 }
791 }
792 }
793
794 assembler->Bind(&if_lhsisnotnumber);
795 {
796 // Check if {lhs} is a JSReceiver.
797 Label if_lhsisreceiver(assembler, Label::kDeferred),
798 if_lhsisnotreceiver(assembler);
799 assembler->Branch(
800 assembler->Int32LessThanOrEqual(
801 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
802 lhs_instance_type),
803 &if_lhsisreceiver, &if_lhsisnotreceiver);
804
805 assembler->Bind(&if_lhsisreceiver);
806 {
807 // Convert {lhs} to a primitive first passing no hint.
808 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
809 var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
810 context, lhs));
811 assembler->Goto(&loop);
812 }
813
814 assembler->Bind(&if_lhsisnotreceiver);
815 {
816 // Check if {rhs} is a JSReceiver.
817 Label if_rhsisreceiver(assembler, Label::kDeferred),
818 if_rhsisnotreceiver(assembler, Label::kDeferred);
819 assembler->Branch(
820 assembler->Int32LessThanOrEqual(
821 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
822 rhs_instance_type),
823 &if_rhsisreceiver, &if_rhsisnotreceiver);
824
825 assembler->Bind(&if_rhsisreceiver);
826 {
827 // Convert {rhs} to a primitive first passing no hint.
828 // TODO(bmeurer): Hook up ToPrimitiveStub here too.
829 var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
830 context, rhs));
831 assembler->Goto(&loop);
832 }
833
834 assembler->Bind(&if_rhsisnotreceiver);
835 {
836 // Convert {lhs} to a Number first.
837 Callable callable =
838 CodeFactory::NonNumberToNumber(assembler->isolate());
839 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
840 assembler->Goto(&loop);
841 }
842 }
843 }
844 }
845 }
846 }
847 }
848 }
Ben Murdochc5610432016-08-08 18:44:38 +0100849 assembler->Bind(&string_add_convert_left);
850 {
851 // Convert {lhs}, which is a Smi, to a String and concatenate the
852 // resulting string with the String {rhs}.
853 Callable callable = CodeFactory::StringAdd(
854 assembler->isolate(), STRING_ADD_CONVERT_LEFT, NOT_TENURED);
855 var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(),
856 var_rhs.value()));
857 assembler->Goto(&end);
858 }
859
860 assembler->Bind(&string_add_convert_right);
861 {
862 // Convert {lhs}, which is a Smi, to a String and concatenate the
863 // resulting string with the String {rhs}.
864 Callable callable = CodeFactory::StringAdd(
865 assembler->isolate(), STRING_ADD_CONVERT_RIGHT, NOT_TENURED);
866 var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(),
867 var_rhs.value()));
868 assembler->Goto(&end);
869 }
Ben Murdochda12d292016-06-02 14:46:10 +0100870
871 assembler->Bind(&do_fadd);
872 {
873 Node* lhs_value = var_fadd_lhs.value();
874 Node* rhs_value = var_fadd_rhs.value();
875 Node* value = assembler->Float64Add(lhs_value, rhs_value);
876 Node* result = assembler->ChangeFloat64ToTagged(value);
Ben Murdochc5610432016-08-08 18:44:38 +0100877 var_result.Bind(result);
878 assembler->Goto(&end);
Ben Murdochda12d292016-06-02 14:46:10 +0100879 }
Ben Murdochc5610432016-08-08 18:44:38 +0100880 assembler->Bind(&end);
881 return var_result.value();
Ben Murdochda12d292016-06-02 14:46:10 +0100882}
883
Ben Murdochc5610432016-08-08 18:44:38 +0100884// static
885compiler::Node* SubtractStub::Generate(CodeStubAssembler* assembler,
886 compiler::Node* left,
887 compiler::Node* right,
888 compiler::Node* context) {
889 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +0100890 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +0100891 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +0100892
893 // Shared entry for floating point subtraction.
Ben Murdochc5610432016-08-08 18:44:38 +0100894 Label do_fsub(assembler), end(assembler);
Ben Murdochda12d292016-06-02 14:46:10 +0100895 Variable var_fsub_lhs(assembler, MachineRepresentation::kFloat64),
896 var_fsub_rhs(assembler, MachineRepresentation::kFloat64);
897
898 // We might need to loop several times due to ToPrimitive and/or ToNumber
899 // conversions.
900 Variable var_lhs(assembler, MachineRepresentation::kTagged),
Ben Murdochc5610432016-08-08 18:44:38 +0100901 var_rhs(assembler, MachineRepresentation::kTagged),
902 var_result(assembler, MachineRepresentation::kTagged);
Ben Murdochda12d292016-06-02 14:46:10 +0100903 Variable* loop_vars[2] = {&var_lhs, &var_rhs};
904 Label loop(assembler, 2, loop_vars);
Ben Murdochc5610432016-08-08 18:44:38 +0100905 var_lhs.Bind(left);
906 var_rhs.Bind(right);
Ben Murdochda12d292016-06-02 14:46:10 +0100907 assembler->Goto(&loop);
908 assembler->Bind(&loop);
909 {
910 // Load the current {lhs} and {rhs} values.
911 Node* lhs = var_lhs.value();
912 Node* rhs = var_rhs.value();
913
914 // Check if the {lhs} is a Smi or a HeapObject.
915 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
916 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
917
918 assembler->Bind(&if_lhsissmi);
919 {
920 // Check if the {rhs} is also a Smi.
921 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
922 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
923 &if_rhsisnotsmi);
924
925 assembler->Bind(&if_rhsissmi);
926 {
927 // Try a fast Smi subtraction first.
928 Node* pair = assembler->SmiSubWithOverflow(lhs, rhs);
929 Node* overflow = assembler->Projection(1, pair);
930
931 // Check if the Smi subtraction overflowed.
932 Label if_overflow(assembler), if_notoverflow(assembler);
933 assembler->Branch(overflow, &if_overflow, &if_notoverflow);
934
935 assembler->Bind(&if_overflow);
936 {
937 // The result doesn't fit into Smi range.
938 var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs));
939 var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs));
940 assembler->Goto(&do_fsub);
941 }
942
943 assembler->Bind(&if_notoverflow);
Ben Murdochc5610432016-08-08 18:44:38 +0100944 var_result.Bind(assembler->Projection(0, pair));
945 assembler->Goto(&end);
Ben Murdochda12d292016-06-02 14:46:10 +0100946 }
947
948 assembler->Bind(&if_rhsisnotsmi);
949 {
950 // Load the map of the {rhs}.
951 Node* rhs_map = assembler->LoadMap(rhs);
952
953 // Check if {rhs} is a HeapNumber.
954 Label if_rhsisnumber(assembler),
955 if_rhsisnotnumber(assembler, Label::kDeferred);
956 Node* number_map = assembler->HeapNumberMapConstant();
957 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
958 &if_rhsisnumber, &if_rhsisnotnumber);
959
960 assembler->Bind(&if_rhsisnumber);
961 {
962 // Perform a floating point subtraction.
963 var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs));
964 var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
965 assembler->Goto(&do_fsub);
966 }
967
968 assembler->Bind(&if_rhsisnotnumber);
969 {
970 // Convert the {rhs} to a Number first.
Ben Murdochc5610432016-08-08 18:44:38 +0100971 Callable callable =
972 CodeFactory::NonNumberToNumber(assembler->isolate());
Ben Murdochda12d292016-06-02 14:46:10 +0100973 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
974 assembler->Goto(&loop);
975 }
976 }
977 }
978
979 assembler->Bind(&if_lhsisnotsmi);
980 {
981 // Load the map of the {lhs}.
982 Node* lhs_map = assembler->LoadMap(lhs);
983
984 // Check if the {lhs} is a HeapNumber.
985 Label if_lhsisnumber(assembler),
986 if_lhsisnotnumber(assembler, Label::kDeferred);
987 Node* number_map = assembler->HeapNumberMapConstant();
988 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
989 &if_lhsisnumber, &if_lhsisnotnumber);
990
991 assembler->Bind(&if_lhsisnumber);
992 {
993 // Check if the {rhs} is a Smi.
994 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
995 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
996 &if_rhsisnotsmi);
997
998 assembler->Bind(&if_rhsissmi);
999 {
1000 // Perform a floating point subtraction.
1001 var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
1002 var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs));
1003 assembler->Goto(&do_fsub);
1004 }
1005
1006 assembler->Bind(&if_rhsisnotsmi);
1007 {
1008 // Load the map of the {rhs}.
1009 Node* rhs_map = assembler->LoadMap(rhs);
1010
1011 // Check if the {rhs} is a HeapNumber.
1012 Label if_rhsisnumber(assembler),
1013 if_rhsisnotnumber(assembler, Label::kDeferred);
1014 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
1015 &if_rhsisnumber, &if_rhsisnotnumber);
1016
1017 assembler->Bind(&if_rhsisnumber);
1018 {
1019 // Perform a floating point subtraction.
1020 var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
1021 var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
1022 assembler->Goto(&do_fsub);
1023 }
1024
1025 assembler->Bind(&if_rhsisnotnumber);
1026 {
1027 // Convert the {rhs} to a Number first.
Ben Murdochc5610432016-08-08 18:44:38 +01001028 Callable callable =
1029 CodeFactory::NonNumberToNumber(assembler->isolate());
Ben Murdochda12d292016-06-02 14:46:10 +01001030 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
1031 assembler->Goto(&loop);
1032 }
1033 }
1034 }
1035
1036 assembler->Bind(&if_lhsisnotnumber);
1037 {
1038 // Convert the {lhs} to a Number first.
Ben Murdochc5610432016-08-08 18:44:38 +01001039 Callable callable =
1040 CodeFactory::NonNumberToNumber(assembler->isolate());
Ben Murdochda12d292016-06-02 14:46:10 +01001041 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
1042 assembler->Goto(&loop);
1043 }
1044 }
1045 }
1046
1047 assembler->Bind(&do_fsub);
1048 {
1049 Node* lhs_value = var_fsub_lhs.value();
1050 Node* rhs_value = var_fsub_rhs.value();
1051 Node* value = assembler->Float64Sub(lhs_value, rhs_value);
Ben Murdochc5610432016-08-08 18:44:38 +01001052 var_result.Bind(assembler->ChangeFloat64ToTagged(value));
1053 assembler->Goto(&end);
1054 }
1055 assembler->Bind(&end);
1056 return var_result.value();
1057}
1058
1059// static
1060compiler::Node* MultiplyStub::Generate(CodeStubAssembler* assembler,
1061 compiler::Node* left,
1062 compiler::Node* right,
1063 compiler::Node* context) {
1064 using compiler::Node;
1065 typedef CodeStubAssembler::Label Label;
1066 typedef CodeStubAssembler::Variable Variable;
1067
1068 // Shared entry point for floating point multiplication.
1069 Label do_fmul(assembler);
1070 Variable var_lhs_float64(assembler, MachineRepresentation::kFloat64),
1071 var_rhs_float64(assembler, MachineRepresentation::kFloat64);
1072
1073 Node* number_map = assembler->HeapNumberMapConstant();
1074
1075 // We might need to loop one or two times due to ToNumber conversions.
1076 Variable var_lhs(assembler, MachineRepresentation::kTagged),
1077 var_rhs(assembler, MachineRepresentation::kTagged);
1078 Variable* loop_variables[] = {&var_lhs, &var_rhs};
1079 Label loop(assembler, 2, loop_variables);
1080 var_lhs.Bind(left);
1081 var_rhs.Bind(right);
1082 assembler->Goto(&loop);
1083 assembler->Bind(&loop);
1084 {
1085 Node* lhs = var_lhs.value();
1086 Node* rhs = var_rhs.value();
1087
1088 Label lhs_is_smi(assembler), lhs_is_not_smi(assembler);
1089 assembler->Branch(assembler->WordIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi);
1090
1091 assembler->Bind(&lhs_is_smi);
1092 {
1093 Label rhs_is_smi(assembler), rhs_is_not_smi(assembler);
1094 assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi,
1095 &rhs_is_not_smi);
1096
1097 assembler->Bind(&rhs_is_smi);
1098 {
1099 // Both {lhs} and {rhs} are Smis. Convert them to double and multiply.
1100 // TODO(epertoso): use SmiMulWithOverflow once available.
1101 var_lhs_float64.Bind(assembler->SmiToFloat64(lhs));
1102 var_rhs_float64.Bind(assembler->SmiToFloat64(rhs));
1103 assembler->Goto(&do_fmul);
1104 }
1105
1106 assembler->Bind(&rhs_is_not_smi);
1107 {
1108 Node* rhs_map = assembler->LoadMap(rhs);
1109
1110 // Check if {rhs} is a HeapNumber.
1111 Label rhs_is_number(assembler),
1112 rhs_is_not_number(assembler, Label::kDeferred);
1113 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
1114 &rhs_is_number, &rhs_is_not_number);
1115
1116 assembler->Bind(&rhs_is_number);
1117 {
1118 // Convert {lhs} to a double and multiply it with the value of {rhs}.
1119 var_lhs_float64.Bind(assembler->SmiToFloat64(lhs));
1120 var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs));
1121 assembler->Goto(&do_fmul);
1122 }
1123
1124 assembler->Bind(&rhs_is_not_number);
1125 {
1126 // Multiplication is commutative, swap {lhs} with {rhs} and loop.
1127 var_lhs.Bind(rhs);
1128 var_rhs.Bind(lhs);
1129 assembler->Goto(&loop);
1130 }
1131 }
1132 }
1133
1134 assembler->Bind(&lhs_is_not_smi);
1135 {
1136 Node* lhs_map = assembler->LoadMap(lhs);
1137
1138 // Check if {lhs} is a HeapNumber.
1139 Label lhs_is_number(assembler),
1140 lhs_is_not_number(assembler, Label::kDeferred);
1141 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
1142 &lhs_is_number, &lhs_is_not_number);
1143
1144 assembler->Bind(&lhs_is_number);
1145 {
1146 // Check if {rhs} is a Smi.
1147 Label rhs_is_smi(assembler), rhs_is_not_smi(assembler);
1148 assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi,
1149 &rhs_is_not_smi);
1150
1151 assembler->Bind(&rhs_is_smi);
1152 {
1153 // Convert {rhs} to a double and multiply it with the value of {lhs}.
1154 var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs));
1155 var_rhs_float64.Bind(assembler->SmiToFloat64(rhs));
1156 assembler->Goto(&do_fmul);
1157 }
1158
1159 assembler->Bind(&rhs_is_not_smi);
1160 {
1161 Node* rhs_map = assembler->LoadMap(rhs);
1162
1163 // Check if {rhs} is a HeapNumber.
1164 Label rhs_is_number(assembler),
1165 rhs_is_not_number(assembler, Label::kDeferred);
1166 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
1167 &rhs_is_number, &rhs_is_not_number);
1168
1169 assembler->Bind(&rhs_is_number);
1170 {
1171 // Both {lhs} and {rhs} are HeapNumbers. Load their values and
1172 // multiply them.
1173 var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs));
1174 var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs));
1175 assembler->Goto(&do_fmul);
1176 }
1177
1178 assembler->Bind(&rhs_is_not_number);
1179 {
1180 // Multiplication is commutative, swap {lhs} with {rhs} and loop.
1181 var_lhs.Bind(rhs);
1182 var_rhs.Bind(lhs);
1183 assembler->Goto(&loop);
1184 }
1185 }
1186 }
1187
1188 assembler->Bind(&lhs_is_not_number);
1189 {
1190 // Convert {lhs} to a Number and loop.
1191 Callable callable =
1192 CodeFactory::NonNumberToNumber(assembler->isolate());
1193 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
1194 assembler->Goto(&loop);
1195 }
1196 }
1197 }
1198
1199 assembler->Bind(&do_fmul);
1200 {
1201 Node* value =
1202 assembler->Float64Mul(var_lhs_float64.value(), var_rhs_float64.value());
Ben Murdochda12d292016-06-02 14:46:10 +01001203 Node* result = assembler->ChangeFloat64ToTagged(value);
Ben Murdochc5610432016-08-08 18:44:38 +01001204 return result;
Ben Murdochda12d292016-06-02 14:46:10 +01001205 }
1206}
1207
Ben Murdochc5610432016-08-08 18:44:38 +01001208// static
1209compiler::Node* DivideStub::Generate(CodeStubAssembler* assembler,
1210 compiler::Node* left,
1211 compiler::Node* right,
1212 compiler::Node* context) {
1213 using compiler::Node;
1214 typedef CodeStubAssembler::Label Label;
1215 typedef CodeStubAssembler::Variable Variable;
1216
1217 // Shared entry point for floating point division.
1218 Label do_fdiv(assembler), end(assembler);
1219 Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64),
1220 var_divisor_float64(assembler, MachineRepresentation::kFloat64);
1221
1222 Node* number_map = assembler->HeapNumberMapConstant();
1223
1224 // We might need to loop one or two times due to ToNumber conversions.
1225 Variable var_dividend(assembler, MachineRepresentation::kTagged),
1226 var_divisor(assembler, MachineRepresentation::kTagged),
1227 var_result(assembler, MachineRepresentation::kTagged);
1228 Variable* loop_variables[] = {&var_dividend, &var_divisor};
1229 Label loop(assembler, 2, loop_variables);
1230 var_dividend.Bind(left);
1231 var_divisor.Bind(right);
1232 assembler->Goto(&loop);
1233 assembler->Bind(&loop);
1234 {
1235 Node* dividend = var_dividend.value();
1236 Node* divisor = var_divisor.value();
1237
1238 Label dividend_is_smi(assembler), dividend_is_not_smi(assembler);
1239 assembler->Branch(assembler->WordIsSmi(dividend), &dividend_is_smi,
1240 &dividend_is_not_smi);
1241
1242 assembler->Bind(&dividend_is_smi);
1243 {
1244 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler);
1245 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi,
1246 &divisor_is_not_smi);
1247
1248 assembler->Bind(&divisor_is_smi);
1249 {
1250 Label bailout(assembler);
1251
1252 // Do floating point division if {divisor} is zero.
1253 assembler->GotoIf(
1254 assembler->WordEqual(divisor, assembler->IntPtrConstant(0)),
1255 &bailout);
1256
1257 // Do floating point division {dividend} is zero and {divisor} is
1258 // negative.
1259 Label dividend_is_zero(assembler), dividend_is_not_zero(assembler);
1260 assembler->Branch(
1261 assembler->WordEqual(dividend, assembler->IntPtrConstant(0)),
1262 &dividend_is_zero, &dividend_is_not_zero);
1263
1264 assembler->Bind(&dividend_is_zero);
1265 {
1266 assembler->GotoIf(
1267 assembler->IntPtrLessThan(divisor, assembler->IntPtrConstant(0)),
1268 &bailout);
1269 assembler->Goto(&dividend_is_not_zero);
1270 }
1271 assembler->Bind(&dividend_is_not_zero);
1272
1273 Node* untagged_divisor = assembler->SmiUntag(divisor);
1274 Node* untagged_dividend = assembler->SmiUntag(dividend);
1275
1276 // Do floating point division if {dividend} is kMinInt (or kMinInt - 1
1277 // if the Smi size is 31) and {divisor} is -1.
1278 Label divisor_is_minus_one(assembler),
1279 divisor_is_not_minus_one(assembler);
1280 assembler->Branch(assembler->Word32Equal(untagged_divisor,
1281 assembler->Int32Constant(-1)),
1282 &divisor_is_minus_one, &divisor_is_not_minus_one);
1283
1284 assembler->Bind(&divisor_is_minus_one);
1285 {
1286 assembler->GotoIf(
1287 assembler->Word32Equal(
1288 untagged_dividend,
1289 assembler->Int32Constant(
1290 kSmiValueSize == 32 ? kMinInt : (kMinInt >> 1))),
1291 &bailout);
1292 assembler->Goto(&divisor_is_not_minus_one);
1293 }
1294 assembler->Bind(&divisor_is_not_minus_one);
1295
1296 // TODO(epertoso): consider adding a machine instruction that returns
1297 // both the result and the remainder.
1298 Node* untagged_result =
1299 assembler->Int32Div(untagged_dividend, untagged_divisor);
1300 Node* truncated =
1301 assembler->IntPtrMul(untagged_result, untagged_divisor);
1302 // Do floating point division if the remainder is not 0.
1303 assembler->GotoIf(
1304 assembler->Word32NotEqual(untagged_dividend, truncated), &bailout);
1305 var_result.Bind(assembler->SmiTag(untagged_result));
1306 assembler->Goto(&end);
1307
1308 // Bailout: convert {dividend} and {divisor} to double and do double
1309 // division.
1310 assembler->Bind(&bailout);
1311 {
1312 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend));
1313 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor));
1314 assembler->Goto(&do_fdiv);
1315 }
1316 }
1317
1318 assembler->Bind(&divisor_is_not_smi);
1319 {
1320 Node* divisor_map = assembler->LoadMap(divisor);
1321
1322 // Check if {divisor} is a HeapNumber.
1323 Label divisor_is_number(assembler),
1324 divisor_is_not_number(assembler, Label::kDeferred);
1325 assembler->Branch(assembler->WordEqual(divisor_map, number_map),
1326 &divisor_is_number, &divisor_is_not_number);
1327
1328 assembler->Bind(&divisor_is_number);
1329 {
1330 // Convert {dividend} to a double and divide it with the value of
1331 // {divisor}.
1332 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend));
1333 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor));
1334 assembler->Goto(&do_fdiv);
1335 }
1336
1337 assembler->Bind(&divisor_is_not_number);
1338 {
1339 // Convert {divisor} to a number and loop.
1340 Callable callable =
1341 CodeFactory::NonNumberToNumber(assembler->isolate());
1342 var_divisor.Bind(assembler->CallStub(callable, context, divisor));
1343 assembler->Goto(&loop);
1344 }
1345 }
1346 }
1347
1348 assembler->Bind(&dividend_is_not_smi);
1349 {
1350 Node* dividend_map = assembler->LoadMap(dividend);
1351
1352 // Check if {dividend} is a HeapNumber.
1353 Label dividend_is_number(assembler),
1354 dividend_is_not_number(assembler, Label::kDeferred);
1355 assembler->Branch(assembler->WordEqual(dividend_map, number_map),
1356 &dividend_is_number, &dividend_is_not_number);
1357
1358 assembler->Bind(&dividend_is_number);
1359 {
1360 // Check if {divisor} is a Smi.
1361 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler);
1362 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi,
1363 &divisor_is_not_smi);
1364
1365 assembler->Bind(&divisor_is_smi);
1366 {
1367 // Convert {divisor} to a double and use it for a floating point
1368 // division.
1369 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend));
1370 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor));
1371 assembler->Goto(&do_fdiv);
1372 }
1373
1374 assembler->Bind(&divisor_is_not_smi);
1375 {
1376 Node* divisor_map = assembler->LoadMap(divisor);
1377
1378 // Check if {divisor} is a HeapNumber.
1379 Label divisor_is_number(assembler),
1380 divisor_is_not_number(assembler, Label::kDeferred);
1381 assembler->Branch(assembler->WordEqual(divisor_map, number_map),
1382 &divisor_is_number, &divisor_is_not_number);
1383
1384 assembler->Bind(&divisor_is_number);
1385 {
1386 // Both {dividend} and {divisor} are HeapNumbers. Load their values
1387 // and divide them.
1388 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend));
1389 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor));
1390 assembler->Goto(&do_fdiv);
1391 }
1392
1393 assembler->Bind(&divisor_is_not_number);
1394 {
1395 // Convert {divisor} to a number and loop.
1396 Callable callable =
1397 CodeFactory::NonNumberToNumber(assembler->isolate());
1398 var_divisor.Bind(assembler->CallStub(callable, context, divisor));
1399 assembler->Goto(&loop);
1400 }
1401 }
1402 }
1403
1404 assembler->Bind(&dividend_is_not_number);
1405 {
1406 // Convert {dividend} to a Number and loop.
1407 Callable callable =
1408 CodeFactory::NonNumberToNumber(assembler->isolate());
1409 var_dividend.Bind(assembler->CallStub(callable, context, dividend));
1410 assembler->Goto(&loop);
1411 }
1412 }
1413 }
1414
1415 assembler->Bind(&do_fdiv);
1416 {
1417 Node* value = assembler->Float64Div(var_dividend_float64.value(),
1418 var_divisor_float64.value());
1419 var_result.Bind(assembler->ChangeFloat64ToTagged(value));
1420 assembler->Goto(&end);
1421 }
1422 assembler->Bind(&end);
1423 return var_result.value();
1424}
1425
1426// static
1427compiler::Node* ModulusStub::Generate(CodeStubAssembler* assembler,
1428 compiler::Node* left,
1429 compiler::Node* right,
1430 compiler::Node* context) {
1431 using compiler::Node;
1432 typedef CodeStubAssembler::Label Label;
1433 typedef CodeStubAssembler::Variable Variable;
1434
1435 // Shared entry point for floating point modulus.
1436 Label do_fmod(assembler);
1437 Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64),
1438 var_divisor_float64(assembler, MachineRepresentation::kFloat64);
1439
1440 Node* number_map = assembler->HeapNumberMapConstant();
1441
1442 // We might need to loop one or two times due to ToNumber conversions.
1443 Variable var_dividend(assembler, MachineRepresentation::kTagged),
1444 var_divisor(assembler, MachineRepresentation::kTagged);
1445 Variable* loop_variables[] = {&var_dividend, &var_divisor};
1446 Label loop(assembler, 2, loop_variables);
1447 var_dividend.Bind(left);
1448 var_divisor.Bind(right);
1449 assembler->Goto(&loop);
1450 assembler->Bind(&loop);
1451 {
1452 Node* dividend = var_dividend.value();
1453 Node* divisor = var_divisor.value();
1454
1455 Label dividend_is_smi(assembler), dividend_is_not_smi(assembler);
1456 assembler->Branch(assembler->WordIsSmi(dividend), &dividend_is_smi,
1457 &dividend_is_not_smi);
1458
1459 assembler->Bind(&dividend_is_smi);
1460 {
1461 Label dividend_is_not_zero(assembler);
1462 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler);
1463 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi,
1464 &divisor_is_not_smi);
1465
1466 assembler->Bind(&divisor_is_smi);
1467 {
1468 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend));
1469 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor));
1470 assembler->Goto(&do_fmod);
1471 }
1472
1473 assembler->Bind(&divisor_is_not_smi);
1474 {
1475 Node* divisor_map = assembler->LoadMap(divisor);
1476
1477 // Check if {divisor} is a HeapNumber.
1478 Label divisor_is_number(assembler),
1479 divisor_is_not_number(assembler, Label::kDeferred);
1480 assembler->Branch(assembler->WordEqual(divisor_map, number_map),
1481 &divisor_is_number, &divisor_is_not_number);
1482
1483 assembler->Bind(&divisor_is_number);
1484 {
1485 // Convert {dividend} to a double and compute its modulus with the
1486 // value of {dividend}.
1487 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend));
1488 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor));
1489 assembler->Goto(&do_fmod);
1490 }
1491
1492 assembler->Bind(&divisor_is_not_number);
1493 {
1494 // Convert {divisor} to a number and loop.
1495 Callable callable =
1496 CodeFactory::NonNumberToNumber(assembler->isolate());
1497 var_divisor.Bind(assembler->CallStub(callable, context, divisor));
1498 assembler->Goto(&loop);
1499 }
1500 }
1501 }
1502
1503 assembler->Bind(&dividend_is_not_smi);
1504 {
1505 Node* dividend_map = assembler->LoadMap(dividend);
1506
1507 // Check if {dividend} is a HeapNumber.
1508 Label dividend_is_number(assembler),
1509 dividend_is_not_number(assembler, Label::kDeferred);
1510 assembler->Branch(assembler->WordEqual(dividend_map, number_map),
1511 &dividend_is_number, &dividend_is_not_number);
1512
1513 assembler->Bind(&dividend_is_number);
1514 {
1515 // Check if {divisor} is a Smi.
1516 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler);
1517 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi,
1518 &divisor_is_not_smi);
1519
1520 assembler->Bind(&divisor_is_smi);
1521 {
1522 // Convert {divisor} to a double and compute {dividend}'s modulus with
1523 // it.
1524 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend));
1525 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor));
1526 assembler->Goto(&do_fmod);
1527 }
1528
1529 assembler->Bind(&divisor_is_not_smi);
1530 {
1531 Node* divisor_map = assembler->LoadMap(divisor);
1532
1533 // Check if {divisor} is a HeapNumber.
1534 Label divisor_is_number(assembler),
1535 divisor_is_not_number(assembler, Label::kDeferred);
1536 assembler->Branch(assembler->WordEqual(divisor_map, number_map),
1537 &divisor_is_number, &divisor_is_not_number);
1538
1539 assembler->Bind(&divisor_is_number);
1540 {
1541 // Both {dividend} and {divisor} are HeapNumbers. Load their values
1542 // and compute their modulus.
1543 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend));
1544 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor));
1545 assembler->Goto(&do_fmod);
1546 }
1547
1548 assembler->Bind(&divisor_is_not_number);
1549 {
1550 // Convert {divisor} to a number and loop.
1551 Callable callable =
1552 CodeFactory::NonNumberToNumber(assembler->isolate());
1553 var_divisor.Bind(assembler->CallStub(callable, context, divisor));
1554 assembler->Goto(&loop);
1555 }
1556 }
1557 }
1558
1559 assembler->Bind(&dividend_is_not_number);
1560 {
1561 // Convert {dividend} to a Number and loop.
1562 Callable callable =
1563 CodeFactory::NonNumberToNumber(assembler->isolate());
1564 var_dividend.Bind(assembler->CallStub(callable, context, dividend));
1565 assembler->Goto(&loop);
1566 }
1567 }
1568 }
1569
1570 assembler->Bind(&do_fmod);
1571 {
1572 Node* value = assembler->Float64Mod(var_dividend_float64.value(),
1573 var_divisor_float64.value());
1574 Node* result = assembler->ChangeFloat64ToTagged(value);
1575 return result;
1576 }
1577}
1578
1579// static
1580compiler::Node* ShiftLeftStub::Generate(CodeStubAssembler* assembler,
1581 compiler::Node* left,
1582 compiler::Node* right,
1583 compiler::Node* context) {
Ben Murdochda12d292016-06-02 14:46:10 +01001584 using compiler::Node;
1585
Ben Murdochc5610432016-08-08 18:44:38 +01001586 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1587 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
1588 Node* shift_count =
1589 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f));
1590 Node* value = assembler->Word32Shl(lhs_value, shift_count);
1591 Node* result = assembler->ChangeInt32ToTagged(value);
1592 return result;
1593}
1594
1595// static
1596compiler::Node* ShiftRightStub::Generate(CodeStubAssembler* assembler,
1597 compiler::Node* left,
1598 compiler::Node* right,
1599 compiler::Node* context) {
1600 using compiler::Node;
1601
1602 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1603 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
1604 Node* shift_count =
1605 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f));
1606 Node* value = assembler->Word32Sar(lhs_value, shift_count);
1607 Node* result = assembler->ChangeInt32ToTagged(value);
1608 return result;
1609}
1610
1611// static
1612compiler::Node* ShiftRightLogicalStub::Generate(CodeStubAssembler* assembler,
1613 compiler::Node* left,
1614 compiler::Node* right,
1615 compiler::Node* context) {
1616 using compiler::Node;
1617
1618 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1619 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
1620 Node* shift_count =
1621 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f));
1622 Node* value = assembler->Word32Shr(lhs_value, shift_count);
1623 Node* result = assembler->ChangeUint32ToTagged(value);
1624 return result;
1625}
1626
1627// static
1628compiler::Node* BitwiseAndStub::Generate(CodeStubAssembler* assembler,
1629 compiler::Node* left,
1630 compiler::Node* right,
1631 compiler::Node* context) {
1632 using compiler::Node;
1633
1634 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1635 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
Ben Murdochda12d292016-06-02 14:46:10 +01001636 Node* value = assembler->Word32And(lhs_value, rhs_value);
1637 Node* result = assembler->ChangeInt32ToTagged(value);
Ben Murdochc5610432016-08-08 18:44:38 +01001638 return result;
Ben Murdochda12d292016-06-02 14:46:10 +01001639}
1640
Ben Murdochc5610432016-08-08 18:44:38 +01001641// static
1642compiler::Node* BitwiseOrStub::Generate(CodeStubAssembler* assembler,
1643 compiler::Node* left,
1644 compiler::Node* right,
1645 compiler::Node* context) {
Ben Murdochda12d292016-06-02 14:46:10 +01001646 using compiler::Node;
1647
Ben Murdochc5610432016-08-08 18:44:38 +01001648 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1649 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
Ben Murdochda12d292016-06-02 14:46:10 +01001650 Node* value = assembler->Word32Or(lhs_value, rhs_value);
1651 Node* result = assembler->ChangeInt32ToTagged(value);
Ben Murdochc5610432016-08-08 18:44:38 +01001652 return result;
Ben Murdochda12d292016-06-02 14:46:10 +01001653}
1654
Ben Murdochc5610432016-08-08 18:44:38 +01001655// static
1656compiler::Node* BitwiseXorStub::Generate(CodeStubAssembler* assembler,
1657 compiler::Node* left,
1658 compiler::Node* right,
1659 compiler::Node* context) {
Ben Murdochda12d292016-06-02 14:46:10 +01001660 using compiler::Node;
1661
Ben Murdochc5610432016-08-08 18:44:38 +01001662 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1663 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
Ben Murdochda12d292016-06-02 14:46:10 +01001664 Node* value = assembler->Word32Xor(lhs_value, rhs_value);
1665 Node* result = assembler->ChangeInt32ToTagged(value);
Ben Murdochc5610432016-08-08 18:44:38 +01001666 return result;
1667}
1668
1669// static
1670compiler::Node* IncStub::Generate(CodeStubAssembler* assembler,
1671 compiler::Node* value,
1672 compiler::Node* context) {
1673 typedef CodeStubAssembler::Label Label;
1674 typedef compiler::Node Node;
1675 typedef CodeStubAssembler::Variable Variable;
1676
1677 // Shared entry for floating point increment.
1678 Label do_finc(assembler), end(assembler);
1679 Variable var_finc_value(assembler, MachineRepresentation::kFloat64);
1680
1681 // We might need to try again due to ToNumber conversion.
1682 Variable value_var(assembler, MachineRepresentation::kTagged);
1683 Variable result_var(assembler, MachineRepresentation::kTagged);
1684 Label start(assembler, &value_var);
1685 value_var.Bind(value);
1686 assembler->Goto(&start);
1687 assembler->Bind(&start);
1688 {
1689 value = value_var.value();
1690
1691 Label if_issmi(assembler), if_isnotsmi(assembler);
1692 assembler->Branch(assembler->WordIsSmi(value), &if_issmi, &if_isnotsmi);
1693
1694 assembler->Bind(&if_issmi);
1695 {
1696 // Try fast Smi addition first.
1697 Node* one = assembler->SmiConstant(Smi::FromInt(1));
1698 Node* pair = assembler->SmiAddWithOverflow(value, one);
1699 Node* overflow = assembler->Projection(1, pair);
1700
1701 // Check if the Smi additon overflowed.
1702 Label if_overflow(assembler), if_notoverflow(assembler);
1703 assembler->Branch(overflow, &if_overflow, &if_notoverflow);
1704
1705 assembler->Bind(&if_notoverflow);
1706 result_var.Bind(assembler->Projection(0, pair));
1707 assembler->Goto(&end);
1708
1709 assembler->Bind(&if_overflow);
1710 {
1711 var_finc_value.Bind(assembler->SmiToFloat64(value));
1712 assembler->Goto(&do_finc);
1713 }
1714 }
1715
1716 assembler->Bind(&if_isnotsmi);
1717 {
1718 // Check if the value is a HeapNumber.
1719 Label if_valueisnumber(assembler),
1720 if_valuenotnumber(assembler, Label::kDeferred);
1721 Node* value_map = assembler->LoadMap(value);
1722 Node* number_map = assembler->HeapNumberMapConstant();
1723 assembler->Branch(assembler->WordEqual(value_map, number_map),
1724 &if_valueisnumber, &if_valuenotnumber);
1725
1726 assembler->Bind(&if_valueisnumber);
1727 {
1728 // Load the HeapNumber value.
1729 var_finc_value.Bind(assembler->LoadHeapNumberValue(value));
1730 assembler->Goto(&do_finc);
1731 }
1732
1733 assembler->Bind(&if_valuenotnumber);
1734 {
1735 // Convert to a Number first and try again.
1736 Callable callable =
1737 CodeFactory::NonNumberToNumber(assembler->isolate());
1738 value_var.Bind(assembler->CallStub(callable, context, value));
1739 assembler->Goto(&start);
1740 }
1741 }
1742 }
1743
1744 assembler->Bind(&do_finc);
1745 {
1746 Node* finc_value = var_finc_value.value();
1747 Node* one = assembler->Float64Constant(1.0);
1748 Node* finc_result = assembler->Float64Add(finc_value, one);
1749 result_var.Bind(assembler->ChangeFloat64ToTagged(finc_result));
1750 assembler->Goto(&end);
1751 }
1752
1753 assembler->Bind(&end);
1754 return result_var.value();
1755}
1756
1757// static
1758compiler::Node* DecStub::Generate(CodeStubAssembler* assembler,
1759 compiler::Node* value,
1760 compiler::Node* context) {
1761 typedef CodeStubAssembler::Label Label;
1762 typedef compiler::Node Node;
1763 typedef CodeStubAssembler::Variable Variable;
1764
1765 // Shared entry for floating point decrement.
1766 Label do_fdec(assembler), end(assembler);
1767 Variable var_fdec_value(assembler, MachineRepresentation::kFloat64);
1768
1769 // We might need to try again due to ToNumber conversion.
1770 Variable value_var(assembler, MachineRepresentation::kTagged);
1771 Variable result_var(assembler, MachineRepresentation::kTagged);
1772 Label start(assembler, &value_var);
1773 value_var.Bind(value);
1774 assembler->Goto(&start);
1775 assembler->Bind(&start);
1776 {
1777 value = value_var.value();
1778
1779 Label if_issmi(assembler), if_isnotsmi(assembler);
1780 assembler->Branch(assembler->WordIsSmi(value), &if_issmi, &if_isnotsmi);
1781
1782 assembler->Bind(&if_issmi);
1783 {
1784 // Try fast Smi subtraction first.
1785 Node* one = assembler->SmiConstant(Smi::FromInt(1));
1786 Node* pair = assembler->SmiSubWithOverflow(value, one);
1787 Node* overflow = assembler->Projection(1, pair);
1788
1789 // Check if the Smi subtraction overflowed.
1790 Label if_overflow(assembler), if_notoverflow(assembler);
1791 assembler->Branch(overflow, &if_overflow, &if_notoverflow);
1792
1793 assembler->Bind(&if_notoverflow);
1794 result_var.Bind(assembler->Projection(0, pair));
1795 assembler->Goto(&end);
1796
1797 assembler->Bind(&if_overflow);
1798 {
1799 var_fdec_value.Bind(assembler->SmiToFloat64(value));
1800 assembler->Goto(&do_fdec);
1801 }
1802 }
1803
1804 assembler->Bind(&if_isnotsmi);
1805 {
1806 // Check if the value is a HeapNumber.
1807 Label if_valueisnumber(assembler),
1808 if_valuenotnumber(assembler, Label::kDeferred);
1809 Node* value_map = assembler->LoadMap(value);
1810 Node* number_map = assembler->HeapNumberMapConstant();
1811 assembler->Branch(assembler->WordEqual(value_map, number_map),
1812 &if_valueisnumber, &if_valuenotnumber);
1813
1814 assembler->Bind(&if_valueisnumber);
1815 {
1816 // Load the HeapNumber value.
1817 var_fdec_value.Bind(assembler->LoadHeapNumberValue(value));
1818 assembler->Goto(&do_fdec);
1819 }
1820
1821 assembler->Bind(&if_valuenotnumber);
1822 {
1823 // Convert to a Number first and try again.
1824 Callable callable =
1825 CodeFactory::NonNumberToNumber(assembler->isolate());
1826 value_var.Bind(assembler->CallStub(callable, context, value));
1827 assembler->Goto(&start);
1828 }
1829 }
1830 }
1831
1832 assembler->Bind(&do_fdec);
1833 {
1834 Node* fdec_value = var_fdec_value.value();
1835 Node* one = assembler->Float64Constant(1.0);
1836 Node* fdec_result = assembler->Float64Sub(fdec_value, one);
1837 result_var.Bind(assembler->ChangeFloat64ToTagged(fdec_result));
1838 assembler->Goto(&end);
1839 }
1840
1841 assembler->Bind(&end);
1842 return result_var.value();
1843}
1844
Ben Murdoch61f157c2016-09-16 13:49:30 +01001845// static
1846compiler::Node* InstanceOfStub::Generate(CodeStubAssembler* assembler,
1847 compiler::Node* object,
1848 compiler::Node* callable,
1849 compiler::Node* context) {
Ben Murdochc5610432016-08-08 18:44:38 +01001850 typedef CodeStubAssembler::Label Label;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001851 typedef CodeStubAssembler::Variable Variable;
Ben Murdochc5610432016-08-08 18:44:38 +01001852
Ben Murdoch61f157c2016-09-16 13:49:30 +01001853 Label return_runtime(assembler, Label::kDeferred), end(assembler);
1854 Variable result(assembler, MachineRepresentation::kTagged);
Ben Murdochc5610432016-08-08 18:44:38 +01001855
1856 // Check if no one installed @@hasInstance somewhere.
1857 assembler->GotoUnless(
1858 assembler->WordEqual(
1859 assembler->LoadObjectField(
1860 assembler->LoadRoot(Heap::kHasInstanceProtectorRootIndex),
1861 PropertyCell::kValueOffset),
1862 assembler->SmiConstant(Smi::FromInt(Isolate::kArrayProtectorValid))),
1863 &return_runtime);
1864
1865 // Check if {callable} is a valid receiver.
1866 assembler->GotoIf(assembler->WordIsSmi(callable), &return_runtime);
1867 assembler->GotoIf(
1868 assembler->Word32Equal(
1869 assembler->Word32And(
1870 assembler->LoadMapBitField(assembler->LoadMap(callable)),
1871 assembler->Int32Constant(1 << Map::kIsCallable)),
1872 assembler->Int32Constant(0)),
1873 &return_runtime);
1874
1875 // Use the inline OrdinaryHasInstance directly.
Ben Murdoch61f157c2016-09-16 13:49:30 +01001876 result.Bind(assembler->OrdinaryHasInstance(context, callable, object));
1877 assembler->Goto(&end);
Ben Murdochc5610432016-08-08 18:44:38 +01001878
1879 // TODO(bmeurer): Use GetPropertyStub here once available.
1880 assembler->Bind(&return_runtime);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001881 {
1882 result.Bind(assembler->CallRuntime(Runtime::kInstanceOf, context, object,
1883 callable));
1884 assembler->Goto(&end);
1885 }
1886
1887 assembler->Bind(&end);
1888 return result.value();
Ben Murdochda12d292016-06-02 14:46:10 +01001889}
1890
1891namespace {
1892
1893enum RelationalComparisonMode {
1894 kLessThan,
1895 kLessThanOrEqual,
1896 kGreaterThan,
1897 kGreaterThanOrEqual
1898};
1899
Ben Murdoch61f157c2016-09-16 13:49:30 +01001900compiler::Node* GenerateAbstractRelationalComparison(
1901 CodeStubAssembler* assembler, RelationalComparisonMode mode,
1902 compiler::Node* lhs, compiler::Node* rhs, compiler::Node* context) {
Ben Murdochc5610432016-08-08 18:44:38 +01001903 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01001904 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +01001905 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +01001906
Ben Murdoch61f157c2016-09-16 13:49:30 +01001907 Label return_true(assembler), return_false(assembler), end(assembler);
1908 Variable result(assembler, MachineRepresentation::kTagged);
Ben Murdochda12d292016-06-02 14:46:10 +01001909
1910 // Shared entry for floating point comparison.
1911 Label do_fcmp(assembler);
1912 Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64),
1913 var_fcmp_rhs(assembler, MachineRepresentation::kFloat64);
1914
1915 // We might need to loop several times due to ToPrimitive and/or ToNumber
1916 // conversions.
1917 Variable var_lhs(assembler, MachineRepresentation::kTagged),
1918 var_rhs(assembler, MachineRepresentation::kTagged);
1919 Variable* loop_vars[2] = {&var_lhs, &var_rhs};
1920 Label loop(assembler, 2, loop_vars);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001921 var_lhs.Bind(lhs);
1922 var_rhs.Bind(rhs);
Ben Murdochda12d292016-06-02 14:46:10 +01001923 assembler->Goto(&loop);
1924 assembler->Bind(&loop);
1925 {
1926 // Load the current {lhs} and {rhs} values.
Ben Murdoch61f157c2016-09-16 13:49:30 +01001927 lhs = var_lhs.value();
1928 rhs = var_rhs.value();
Ben Murdochda12d292016-06-02 14:46:10 +01001929
1930 // Check if the {lhs} is a Smi or a HeapObject.
1931 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
1932 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
1933
1934 assembler->Bind(&if_lhsissmi);
1935 {
1936 // Check if {rhs} is a Smi or a HeapObject.
1937 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
1938 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
1939 &if_rhsisnotsmi);
1940
1941 assembler->Bind(&if_rhsissmi);
1942 {
1943 // Both {lhs} and {rhs} are Smi, so just perform a fast Smi comparison.
1944 switch (mode) {
1945 case kLessThan:
1946 assembler->BranchIfSmiLessThan(lhs, rhs, &return_true,
1947 &return_false);
1948 break;
1949 case kLessThanOrEqual:
1950 assembler->BranchIfSmiLessThanOrEqual(lhs, rhs, &return_true,
1951 &return_false);
1952 break;
1953 case kGreaterThan:
1954 assembler->BranchIfSmiLessThan(rhs, lhs, &return_true,
1955 &return_false);
1956 break;
1957 case kGreaterThanOrEqual:
1958 assembler->BranchIfSmiLessThanOrEqual(rhs, lhs, &return_true,
1959 &return_false);
1960 break;
1961 }
1962 }
1963
1964 assembler->Bind(&if_rhsisnotsmi);
1965 {
1966 // Load the map of {rhs}.
1967 Node* rhs_map = assembler->LoadMap(rhs);
1968
1969 // Check if the {rhs} is a HeapNumber.
1970 Node* number_map = assembler->HeapNumberMapConstant();
1971 Label if_rhsisnumber(assembler),
1972 if_rhsisnotnumber(assembler, Label::kDeferred);
1973 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
1974 &if_rhsisnumber, &if_rhsisnotnumber);
1975
1976 assembler->Bind(&if_rhsisnumber);
1977 {
1978 // Convert the {lhs} and {rhs} to floating point values, and
1979 // perform a floating point comparison.
1980 var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs));
1981 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
1982 assembler->Goto(&do_fcmp);
1983 }
1984
1985 assembler->Bind(&if_rhsisnotnumber);
1986 {
1987 // Convert the {rhs} to a Number; we don't need to perform the
1988 // dedicated ToPrimitive(rhs, hint Number) operation, as the
1989 // ToNumber(rhs) will by itself already invoke ToPrimitive with
1990 // a Number hint.
1991 Callable callable =
1992 CodeFactory::NonNumberToNumber(assembler->isolate());
1993 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
1994 assembler->Goto(&loop);
1995 }
1996 }
1997 }
1998
1999 assembler->Bind(&if_lhsisnotsmi);
2000 {
2001 // Load the HeapNumber map for later comparisons.
2002 Node* number_map = assembler->HeapNumberMapConstant();
2003
2004 // Load the map of {lhs}.
2005 Node* lhs_map = assembler->LoadMap(lhs);
2006
2007 // Check if {rhs} is a Smi or a HeapObject.
2008 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
2009 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
2010 &if_rhsisnotsmi);
2011
2012 assembler->Bind(&if_rhsissmi);
2013 {
2014 // Check if the {lhs} is a HeapNumber.
2015 Label if_lhsisnumber(assembler),
2016 if_lhsisnotnumber(assembler, Label::kDeferred);
2017 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
2018 &if_lhsisnumber, &if_lhsisnotnumber);
2019
2020 assembler->Bind(&if_lhsisnumber);
2021 {
2022 // Convert the {lhs} and {rhs} to floating point values, and
2023 // perform a floating point comparison.
2024 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
2025 var_fcmp_rhs.Bind(assembler->SmiToFloat64(rhs));
2026 assembler->Goto(&do_fcmp);
2027 }
2028
2029 assembler->Bind(&if_lhsisnotnumber);
2030 {
2031 // Convert the {lhs} to a Number; we don't need to perform the
2032 // dedicated ToPrimitive(lhs, hint Number) operation, as the
2033 // ToNumber(lhs) will by itself already invoke ToPrimitive with
2034 // a Number hint.
2035 Callable callable =
2036 CodeFactory::NonNumberToNumber(assembler->isolate());
2037 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
2038 assembler->Goto(&loop);
2039 }
2040 }
2041
2042 assembler->Bind(&if_rhsisnotsmi);
2043 {
2044 // Load the map of {rhs}.
2045 Node* rhs_map = assembler->LoadMap(rhs);
2046
2047 // Check if {lhs} is a HeapNumber.
2048 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler);
2049 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
2050 &if_lhsisnumber, &if_lhsisnotnumber);
2051
2052 assembler->Bind(&if_lhsisnumber);
2053 {
2054 // Check if {rhs} is also a HeapNumber.
2055 Label if_rhsisnumber(assembler),
2056 if_rhsisnotnumber(assembler, Label::kDeferred);
2057 assembler->Branch(assembler->WordEqual(lhs_map, rhs_map),
2058 &if_rhsisnumber, &if_rhsisnotnumber);
2059
2060 assembler->Bind(&if_rhsisnumber);
2061 {
2062 // Convert the {lhs} and {rhs} to floating point values, and
2063 // perform a floating point comparison.
2064 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
2065 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
2066 assembler->Goto(&do_fcmp);
2067 }
2068
2069 assembler->Bind(&if_rhsisnotnumber);
2070 {
2071 // Convert the {rhs} to a Number; we don't need to perform
2072 // dedicated ToPrimitive(rhs, hint Number) operation, as the
2073 // ToNumber(rhs) will by itself already invoke ToPrimitive with
2074 // a Number hint.
2075 Callable callable =
2076 CodeFactory::NonNumberToNumber(assembler->isolate());
2077 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
2078 assembler->Goto(&loop);
2079 }
2080 }
2081
2082 assembler->Bind(&if_lhsisnotnumber);
2083 {
2084 // Load the instance type of {lhs}.
2085 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map);
2086
2087 // Check if {lhs} is a String.
2088 Label if_lhsisstring(assembler),
2089 if_lhsisnotstring(assembler, Label::kDeferred);
2090 assembler->Branch(assembler->Int32LessThan(
2091 lhs_instance_type,
2092 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
2093 &if_lhsisstring, &if_lhsisnotstring);
2094
2095 assembler->Bind(&if_lhsisstring);
2096 {
2097 // Load the instance type of {rhs}.
2098 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
2099
2100 // Check if {rhs} is also a String.
Ben Murdoch61f157c2016-09-16 13:49:30 +01002101 Label if_rhsisstring(assembler, Label::kDeferred),
Ben Murdochda12d292016-06-02 14:46:10 +01002102 if_rhsisnotstring(assembler, Label::kDeferred);
2103 assembler->Branch(assembler->Int32LessThan(
2104 rhs_instance_type, assembler->Int32Constant(
2105 FIRST_NONSTRING_TYPE)),
2106 &if_rhsisstring, &if_rhsisnotstring);
2107
2108 assembler->Bind(&if_rhsisstring);
2109 {
2110 // Both {lhs} and {rhs} are strings.
2111 switch (mode) {
2112 case kLessThan:
Ben Murdoch61f157c2016-09-16 13:49:30 +01002113 result.Bind(assembler->CallStub(
Ben Murdochda12d292016-06-02 14:46:10 +01002114 CodeFactory::StringLessThan(assembler->isolate()),
Ben Murdoch61f157c2016-09-16 13:49:30 +01002115 context, lhs, rhs));
2116 assembler->Goto(&end);
Ben Murdochda12d292016-06-02 14:46:10 +01002117 break;
2118 case kLessThanOrEqual:
Ben Murdoch61f157c2016-09-16 13:49:30 +01002119 result.Bind(assembler->CallStub(
Ben Murdochda12d292016-06-02 14:46:10 +01002120 CodeFactory::StringLessThanOrEqual(assembler->isolate()),
Ben Murdoch61f157c2016-09-16 13:49:30 +01002121 context, lhs, rhs));
2122 assembler->Goto(&end);
Ben Murdochda12d292016-06-02 14:46:10 +01002123 break;
2124 case kGreaterThan:
Ben Murdoch61f157c2016-09-16 13:49:30 +01002125 result.Bind(assembler->CallStub(
Ben Murdochda12d292016-06-02 14:46:10 +01002126 CodeFactory::StringGreaterThan(assembler->isolate()),
Ben Murdoch61f157c2016-09-16 13:49:30 +01002127 context, lhs, rhs));
2128 assembler->Goto(&end);
Ben Murdochda12d292016-06-02 14:46:10 +01002129 break;
2130 case kGreaterThanOrEqual:
Ben Murdoch61f157c2016-09-16 13:49:30 +01002131 result.Bind(
2132 assembler->CallStub(CodeFactory::StringGreaterThanOrEqual(
Ben Murdochda12d292016-06-02 14:46:10 +01002133 assembler->isolate()),
Ben Murdoch61f157c2016-09-16 13:49:30 +01002134 context, lhs, rhs));
2135 assembler->Goto(&end);
Ben Murdochda12d292016-06-02 14:46:10 +01002136 break;
2137 }
2138 }
2139
2140 assembler->Bind(&if_rhsisnotstring);
2141 {
2142 // The {lhs} is a String, while {rhs} is neither a Number nor a
2143 // String, so we need to call ToPrimitive(rhs, hint Number) if
2144 // {rhs} is a receiver or ToNumber(lhs) and ToNumber(rhs) in the
2145 // other cases.
2146 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2147 Label if_rhsisreceiver(assembler, Label::kDeferred),
2148 if_rhsisnotreceiver(assembler, Label::kDeferred);
2149 assembler->Branch(
2150 assembler->Int32LessThanOrEqual(
2151 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
2152 rhs_instance_type),
2153 &if_rhsisreceiver, &if_rhsisnotreceiver);
2154
2155 assembler->Bind(&if_rhsisreceiver);
2156 {
2157 // Convert {rhs} to a primitive first passing Number hint.
2158 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
2159 var_rhs.Bind(assembler->CallRuntime(
2160 Runtime::kToPrimitive_Number, context, rhs));
2161 assembler->Goto(&loop);
2162 }
2163
2164 assembler->Bind(&if_rhsisnotreceiver);
2165 {
2166 // Convert both {lhs} and {rhs} to Number.
2167 Callable callable = CodeFactory::ToNumber(assembler->isolate());
2168 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
2169 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
2170 assembler->Goto(&loop);
2171 }
2172 }
2173 }
2174
2175 assembler->Bind(&if_lhsisnotstring);
2176 {
2177 // The {lhs} is neither a Number nor a String, so we need to call
2178 // ToPrimitive(lhs, hint Number) if {lhs} is a receiver or
2179 // ToNumber(lhs) and ToNumber(rhs) in the other cases.
2180 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2181 Label if_lhsisreceiver(assembler, Label::kDeferred),
2182 if_lhsisnotreceiver(assembler, Label::kDeferred);
2183 assembler->Branch(
2184 assembler->Int32LessThanOrEqual(
2185 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
2186 lhs_instance_type),
2187 &if_lhsisreceiver, &if_lhsisnotreceiver);
2188
2189 assembler->Bind(&if_lhsisreceiver);
2190 {
2191 // Convert {lhs} to a primitive first passing Number hint.
2192 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
2193 var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive_Number,
2194 context, lhs));
2195 assembler->Goto(&loop);
2196 }
2197
2198 assembler->Bind(&if_lhsisnotreceiver);
2199 {
2200 // Convert both {lhs} and {rhs} to Number.
2201 Callable callable = CodeFactory::ToNumber(assembler->isolate());
2202 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
2203 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
2204 assembler->Goto(&loop);
2205 }
2206 }
2207 }
2208 }
2209 }
2210 }
2211
2212 assembler->Bind(&do_fcmp);
2213 {
2214 // Load the {lhs} and {rhs} floating point values.
2215 Node* lhs = var_fcmp_lhs.value();
2216 Node* rhs = var_fcmp_rhs.value();
2217
2218 // Perform a fast floating point comparison.
2219 switch (mode) {
2220 case kLessThan:
2221 assembler->BranchIfFloat64LessThan(lhs, rhs, &return_true,
2222 &return_false);
2223 break;
2224 case kLessThanOrEqual:
2225 assembler->BranchIfFloat64LessThanOrEqual(lhs, rhs, &return_true,
2226 &return_false);
2227 break;
2228 case kGreaterThan:
2229 assembler->BranchIfFloat64GreaterThan(lhs, rhs, &return_true,
2230 &return_false);
2231 break;
2232 case kGreaterThanOrEqual:
2233 assembler->BranchIfFloat64GreaterThanOrEqual(lhs, rhs, &return_true,
2234 &return_false);
2235 break;
2236 }
2237 }
2238
2239 assembler->Bind(&return_true);
Ben Murdoch61f157c2016-09-16 13:49:30 +01002240 {
2241 result.Bind(assembler->BooleanConstant(true));
2242 assembler->Goto(&end);
2243 }
Ben Murdochda12d292016-06-02 14:46:10 +01002244
2245 assembler->Bind(&return_false);
Ben Murdoch61f157c2016-09-16 13:49:30 +01002246 {
2247 result.Bind(assembler->BooleanConstant(false));
2248 assembler->Goto(&end);
2249 }
2250
2251 assembler->Bind(&end);
2252 return result.value();
Ben Murdochda12d292016-06-02 14:46:10 +01002253}
2254
2255enum ResultMode { kDontNegateResult, kNegateResult };
2256
Ben Murdochc5610432016-08-08 18:44:38 +01002257void GenerateEqual_Same(CodeStubAssembler* assembler, compiler::Node* value,
2258 CodeStubAssembler::Label* if_equal,
2259 CodeStubAssembler::Label* if_notequal) {
Ben Murdochda12d292016-06-02 14:46:10 +01002260 // In case of abstract or strict equality checks, we need additional checks
2261 // for NaN values because they are not considered equal, even if both the
2262 // left and the right hand side reference exactly the same value.
2263 // TODO(bmeurer): This seems to violate the SIMD.js specification, but it
2264 // seems to be what is tested in the current SIMD.js testsuite.
2265
Ben Murdochc5610432016-08-08 18:44:38 +01002266 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01002267 typedef compiler::Node Node;
2268
2269 // Check if {value} is a Smi or a HeapObject.
2270 Label if_valueissmi(assembler), if_valueisnotsmi(assembler);
2271 assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi,
2272 &if_valueisnotsmi);
2273
2274 assembler->Bind(&if_valueisnotsmi);
2275 {
2276 // Load the map of {value}.
2277 Node* value_map = assembler->LoadMap(value);
2278
2279 // Check if {value} (and therefore {rhs}) is a HeapNumber.
2280 Node* number_map = assembler->HeapNumberMapConstant();
2281 Label if_valueisnumber(assembler), if_valueisnotnumber(assembler);
2282 assembler->Branch(assembler->WordEqual(value_map, number_map),
2283 &if_valueisnumber, &if_valueisnotnumber);
2284
2285 assembler->Bind(&if_valueisnumber);
2286 {
2287 // Convert {value} (and therefore {rhs}) to floating point value.
2288 Node* value_value = assembler->LoadHeapNumberValue(value);
2289
2290 // Check if the HeapNumber value is a NaN.
2291 assembler->BranchIfFloat64IsNaN(value_value, if_notequal, if_equal);
2292 }
2293
2294 assembler->Bind(&if_valueisnotnumber);
2295 assembler->Goto(if_equal);
2296 }
2297
2298 assembler->Bind(&if_valueissmi);
2299 assembler->Goto(if_equal);
2300}
2301
2302void GenerateEqual_Simd128Value_HeapObject(
Ben Murdochc5610432016-08-08 18:44:38 +01002303 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* lhs_map,
2304 compiler::Node* rhs, compiler::Node* rhs_map,
2305 CodeStubAssembler::Label* if_equal, CodeStubAssembler::Label* if_notequal) {
2306 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01002307 typedef compiler::Node Node;
2308
2309 // Check if {lhs} and {rhs} have the same map.
2310 Label if_mapsame(assembler), if_mapnotsame(assembler);
2311 assembler->Branch(assembler->WordEqual(lhs_map, rhs_map), &if_mapsame,
2312 &if_mapnotsame);
2313
2314 assembler->Bind(&if_mapsame);
2315 {
2316 // Both {lhs} and {rhs} are Simd128Values with the same map, need special
2317 // handling for Float32x4 because of NaN comparisons.
2318 Label if_float32x4(assembler), if_notfloat32x4(assembler);
2319 Node* float32x4_map =
2320 assembler->HeapConstant(assembler->factory()->float32x4_map());
2321 assembler->Branch(assembler->WordEqual(lhs_map, float32x4_map),
2322 &if_float32x4, &if_notfloat32x4);
2323
2324 assembler->Bind(&if_float32x4);
2325 {
2326 // Both {lhs} and {rhs} are Float32x4, compare the lanes individually
2327 // using a floating point comparison.
2328 for (int offset = Float32x4::kValueOffset - kHeapObjectTag;
2329 offset < Float32x4::kSize - kHeapObjectTag;
2330 offset += sizeof(float)) {
2331 // Load the floating point values for {lhs} and {rhs}.
2332 Node* lhs_value = assembler->Load(MachineType::Float32(), lhs,
2333 assembler->IntPtrConstant(offset));
2334 Node* rhs_value = assembler->Load(MachineType::Float32(), rhs,
2335 assembler->IntPtrConstant(offset));
2336
2337 // Perform a floating point comparison.
2338 Label if_valueequal(assembler), if_valuenotequal(assembler);
2339 assembler->Branch(assembler->Float32Equal(lhs_value, rhs_value),
2340 &if_valueequal, &if_valuenotequal);
2341 assembler->Bind(&if_valuenotequal);
2342 assembler->Goto(if_notequal);
2343 assembler->Bind(&if_valueequal);
2344 }
2345
2346 // All 4 lanes match, {lhs} and {rhs} considered equal.
2347 assembler->Goto(if_equal);
2348 }
2349
2350 assembler->Bind(&if_notfloat32x4);
2351 {
2352 // For other Simd128Values we just perform a bitwise comparison.
2353 for (int offset = Simd128Value::kValueOffset - kHeapObjectTag;
2354 offset < Simd128Value::kSize - kHeapObjectTag;
2355 offset += kPointerSize) {
2356 // Load the word values for {lhs} and {rhs}.
2357 Node* lhs_value = assembler->Load(MachineType::Pointer(), lhs,
2358 assembler->IntPtrConstant(offset));
2359 Node* rhs_value = assembler->Load(MachineType::Pointer(), rhs,
2360 assembler->IntPtrConstant(offset));
2361
2362 // Perform a bitwise word-comparison.
2363 Label if_valueequal(assembler), if_valuenotequal(assembler);
2364 assembler->Branch(assembler->WordEqual(lhs_value, rhs_value),
2365 &if_valueequal, &if_valuenotequal);
2366 assembler->Bind(&if_valuenotequal);
2367 assembler->Goto(if_notequal);
2368 assembler->Bind(&if_valueequal);
2369 }
2370
2371 // Bitwise comparison succeeded, {lhs} and {rhs} considered equal.
2372 assembler->Goto(if_equal);
2373 }
2374 }
2375
2376 assembler->Bind(&if_mapnotsame);
2377 assembler->Goto(if_notequal);
2378}
2379
2380// ES6 section 7.2.12 Abstract Equality Comparison
Ben Murdoch61f157c2016-09-16 13:49:30 +01002381compiler::Node* GenerateEqual(CodeStubAssembler* assembler, ResultMode mode,
2382 compiler::Node* lhs, compiler::Node* rhs,
2383 compiler::Node* context) {
Ben Murdochda12d292016-06-02 14:46:10 +01002384 // This is a slightly optimized version of Object::Equals represented as
2385 // scheduled TurboFan graph utilizing the CodeStubAssembler. Whenever you
2386 // change something functionality wise in here, remember to update the
2387 // Object::Equals method as well.
Ben Murdochc5610432016-08-08 18:44:38 +01002388 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01002389 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +01002390 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +01002391
Ben Murdoch61f157c2016-09-16 13:49:30 +01002392 Label if_equal(assembler), if_notequal(assembler),
2393 do_rhsstringtonumber(assembler, Label::kDeferred), end(assembler);
2394 Variable result(assembler, MachineRepresentation::kTagged);
Ben Murdochda12d292016-06-02 14:46:10 +01002395
2396 // Shared entry for floating point comparison.
2397 Label do_fcmp(assembler);
2398 Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64),
2399 var_fcmp_rhs(assembler, MachineRepresentation::kFloat64);
2400
2401 // We might need to loop several times due to ToPrimitive and/or ToNumber
2402 // conversions.
2403 Variable var_lhs(assembler, MachineRepresentation::kTagged),
2404 var_rhs(assembler, MachineRepresentation::kTagged);
2405 Variable* loop_vars[2] = {&var_lhs, &var_rhs};
2406 Label loop(assembler, 2, loop_vars);
Ben Murdoch61f157c2016-09-16 13:49:30 +01002407 var_lhs.Bind(lhs);
2408 var_rhs.Bind(rhs);
Ben Murdochda12d292016-06-02 14:46:10 +01002409 assembler->Goto(&loop);
2410 assembler->Bind(&loop);
2411 {
2412 // Load the current {lhs} and {rhs} values.
Ben Murdoch61f157c2016-09-16 13:49:30 +01002413 lhs = var_lhs.value();
2414 rhs = var_rhs.value();
Ben Murdochda12d292016-06-02 14:46:10 +01002415
2416 // Check if {lhs} and {rhs} refer to the same object.
2417 Label if_same(assembler), if_notsame(assembler);
2418 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
2419
2420 assembler->Bind(&if_same);
2421 {
2422 // The {lhs} and {rhs} reference the exact same value, yet we need special
2423 // treatment for HeapNumber, as NaN is not equal to NaN.
2424 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal);
2425 }
2426
2427 assembler->Bind(&if_notsame);
2428 {
2429 // Check if {lhs} is a Smi or a HeapObject.
2430 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
2431 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi,
2432 &if_lhsisnotsmi);
2433
2434 assembler->Bind(&if_lhsissmi);
2435 {
2436 // Check if {rhs} is a Smi or a HeapObject.
2437 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
2438 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
2439 &if_rhsisnotsmi);
2440
2441 assembler->Bind(&if_rhsissmi);
Ben Murdoch61f157c2016-09-16 13:49:30 +01002442 // We have already checked for {lhs} and {rhs} being the same value, so
2443 // if both are Smis when we get here they must not be equal.
Ben Murdochda12d292016-06-02 14:46:10 +01002444 assembler->Goto(&if_notequal);
2445
2446 assembler->Bind(&if_rhsisnotsmi);
2447 {
2448 // Load the map of {rhs}.
2449 Node* rhs_map = assembler->LoadMap(rhs);
2450
2451 // Check if {rhs} is a HeapNumber.
2452 Node* number_map = assembler->HeapNumberMapConstant();
Ben Murdoch61f157c2016-09-16 13:49:30 +01002453 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler);
Ben Murdochda12d292016-06-02 14:46:10 +01002454 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
2455 &if_rhsisnumber, &if_rhsisnotnumber);
2456
2457 assembler->Bind(&if_rhsisnumber);
2458 {
2459 // Convert {lhs} and {rhs} to floating point values, and
2460 // perform a floating point comparison.
2461 var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs));
2462 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
2463 assembler->Goto(&do_fcmp);
2464 }
2465
2466 assembler->Bind(&if_rhsisnotnumber);
2467 {
2468 // Load the instance type of the {rhs}.
2469 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
2470
2471 // Check if the {rhs} is a String.
2472 Label if_rhsisstring(assembler, Label::kDeferred),
Ben Murdoch61f157c2016-09-16 13:49:30 +01002473 if_rhsisnotstring(assembler);
Ben Murdochda12d292016-06-02 14:46:10 +01002474 assembler->Branch(assembler->Int32LessThan(
2475 rhs_instance_type, assembler->Int32Constant(
2476 FIRST_NONSTRING_TYPE)),
2477 &if_rhsisstring, &if_rhsisnotstring);
2478
2479 assembler->Bind(&if_rhsisstring);
2480 {
Ben Murdoch61f157c2016-09-16 13:49:30 +01002481 // The {rhs} is a String and the {lhs} is a Smi; we need
2482 // to convert the {rhs} to a Number and compare the output to
2483 // the Number on the {lhs}.
2484 assembler->Goto(&do_rhsstringtonumber);
Ben Murdochda12d292016-06-02 14:46:10 +01002485 }
2486
2487 assembler->Bind(&if_rhsisnotstring);
2488 {
2489 // Check if the {rhs} is a Boolean.
2490 Node* boolean_map = assembler->BooleanMapConstant();
Ben Murdoch61f157c2016-09-16 13:49:30 +01002491 Label if_rhsisboolean(assembler), if_rhsisnotboolean(assembler);
Ben Murdochda12d292016-06-02 14:46:10 +01002492 assembler->Branch(assembler->WordEqual(rhs_map, boolean_map),
2493 &if_rhsisboolean, &if_rhsisnotboolean);
2494
2495 assembler->Bind(&if_rhsisboolean);
2496 {
2497 // The {rhs} is a Boolean, load its number value.
2498 var_rhs.Bind(
2499 assembler->LoadObjectField(rhs, Oddball::kToNumberOffset));
2500 assembler->Goto(&loop);
2501 }
2502
2503 assembler->Bind(&if_rhsisnotboolean);
2504 {
2505 // Check if the {rhs} is a Receiver.
2506 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2507 Label if_rhsisreceiver(assembler, Label::kDeferred),
Ben Murdoch61f157c2016-09-16 13:49:30 +01002508 if_rhsisnotreceiver(assembler);
Ben Murdochda12d292016-06-02 14:46:10 +01002509 assembler->Branch(
2510 assembler->Int32LessThanOrEqual(
2511 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
2512 rhs_instance_type),
2513 &if_rhsisreceiver, &if_rhsisnotreceiver);
2514
2515 assembler->Bind(&if_rhsisreceiver);
2516 {
2517 // Convert {rhs} to a primitive first (passing no hint).
2518 // TODO(bmeurer): Hook up ToPrimitiveStub here once it exists.
2519 var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
2520 context, rhs));
2521 assembler->Goto(&loop);
2522 }
2523
2524 assembler->Bind(&if_rhsisnotreceiver);
2525 assembler->Goto(&if_notequal);
2526 }
2527 }
2528 }
2529 }
2530 }
2531
2532 assembler->Bind(&if_lhsisnotsmi);
2533 {
2534 // Check if {rhs} is a Smi or a HeapObject.
2535 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
2536 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
2537 &if_rhsisnotsmi);
2538
2539 assembler->Bind(&if_rhsissmi);
2540 {
2541 // The {lhs} is a HeapObject and the {rhs} is a Smi; swapping {lhs}
2542 // and {rhs} is not observable and doesn't matter for the result, so
2543 // we can just swap them and use the Smi handling above (for {lhs}
2544 // being a Smi).
2545 var_lhs.Bind(rhs);
2546 var_rhs.Bind(lhs);
2547 assembler->Goto(&loop);
2548 }
2549
2550 assembler->Bind(&if_rhsisnotsmi);
2551 {
2552 Label if_lhsisstring(assembler), if_lhsisnumber(assembler),
2553 if_lhsissymbol(assembler), if_lhsissimd128value(assembler),
2554 if_lhsisoddball(assembler), if_lhsisreceiver(assembler);
2555
2556 // Both {lhs} and {rhs} are HeapObjects, load their maps
2557 // and their instance types.
2558 Node* lhs_map = assembler->LoadMap(lhs);
2559 Node* rhs_map = assembler->LoadMap(rhs);
2560
2561 // Load the instance types of {lhs} and {rhs}.
2562 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map);
2563 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
2564
2565 // Dispatch based on the instance type of {lhs}.
2566 size_t const kNumCases = FIRST_NONSTRING_TYPE + 4;
2567 Label* case_labels[kNumCases];
2568 int32_t case_values[kNumCases];
2569 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) {
2570 case_labels[i] = new Label(assembler);
2571 case_values[i] = i;
2572 }
2573 case_labels[FIRST_NONSTRING_TYPE + 0] = &if_lhsisnumber;
2574 case_values[FIRST_NONSTRING_TYPE + 0] = HEAP_NUMBER_TYPE;
2575 case_labels[FIRST_NONSTRING_TYPE + 1] = &if_lhsissymbol;
2576 case_values[FIRST_NONSTRING_TYPE + 1] = SYMBOL_TYPE;
2577 case_labels[FIRST_NONSTRING_TYPE + 2] = &if_lhsissimd128value;
2578 case_values[FIRST_NONSTRING_TYPE + 2] = SIMD128_VALUE_TYPE;
2579 case_labels[FIRST_NONSTRING_TYPE + 3] = &if_lhsisoddball;
2580 case_values[FIRST_NONSTRING_TYPE + 3] = ODDBALL_TYPE;
2581 assembler->Switch(lhs_instance_type, &if_lhsisreceiver, case_values,
2582 case_labels, arraysize(case_values));
2583 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) {
2584 assembler->Bind(case_labels[i]);
2585 assembler->Goto(&if_lhsisstring);
2586 delete case_labels[i];
2587 }
2588
2589 assembler->Bind(&if_lhsisstring);
2590 {
2591 // Check if {rhs} is also a String.
Ben Murdoch61f157c2016-09-16 13:49:30 +01002592 Label if_rhsisstring(assembler, Label::kDeferred),
2593 if_rhsisnotstring(assembler);
Ben Murdochda12d292016-06-02 14:46:10 +01002594 assembler->Branch(assembler->Int32LessThan(
2595 rhs_instance_type, assembler->Int32Constant(
2596 FIRST_NONSTRING_TYPE)),
2597 &if_rhsisstring, &if_rhsisnotstring);
2598
2599 assembler->Bind(&if_rhsisstring);
2600 {
2601 // Both {lhs} and {rhs} are of type String, just do the
2602 // string comparison then.
2603 Callable callable =
2604 (mode == kDontNegateResult)
2605 ? CodeFactory::StringEqual(assembler->isolate())
2606 : CodeFactory::StringNotEqual(assembler->isolate());
Ben Murdoch61f157c2016-09-16 13:49:30 +01002607 result.Bind(assembler->CallStub(callable, context, lhs, rhs));
2608 assembler->Goto(&end);
Ben Murdochda12d292016-06-02 14:46:10 +01002609 }
2610
2611 assembler->Bind(&if_rhsisnotstring);
2612 {
2613 // The {lhs} is a String and the {rhs} is some other HeapObject.
2614 // Swapping {lhs} and {rhs} is not observable and doesn't matter
2615 // for the result, so we can just swap them and use the String
2616 // handling below (for {rhs} being a String).
2617 var_lhs.Bind(rhs);
2618 var_rhs.Bind(lhs);
2619 assembler->Goto(&loop);
2620 }
2621 }
2622
2623 assembler->Bind(&if_lhsisnumber);
2624 {
2625 // Check if {rhs} is also a HeapNumber.
Ben Murdoch61f157c2016-09-16 13:49:30 +01002626 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler);
Ben Murdochda12d292016-06-02 14:46:10 +01002627 assembler->Branch(
2628 assembler->Word32Equal(lhs_instance_type, rhs_instance_type),
2629 &if_rhsisnumber, &if_rhsisnotnumber);
2630
2631 assembler->Bind(&if_rhsisnumber);
2632 {
2633 // Convert {lhs} and {rhs} to floating point values, and
2634 // perform a floating point comparison.
2635 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
2636 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
2637 assembler->Goto(&do_fcmp);
2638 }
2639
2640 assembler->Bind(&if_rhsisnotnumber);
2641 {
2642 // The {lhs} is a Number, the {rhs} is some other HeapObject.
2643 Label if_rhsisstring(assembler, Label::kDeferred),
2644 if_rhsisnotstring(assembler);
2645 assembler->Branch(
2646 assembler->Int32LessThan(
2647 rhs_instance_type,
2648 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
2649 &if_rhsisstring, &if_rhsisnotstring);
2650
2651 assembler->Bind(&if_rhsisstring);
2652 {
2653 // The {rhs} is a String and the {lhs} is a HeapNumber; we need
2654 // to convert the {rhs} to a Number and compare the output to
2655 // the Number on the {lhs}.
Ben Murdoch61f157c2016-09-16 13:49:30 +01002656 assembler->Goto(&do_rhsstringtonumber);
Ben Murdochda12d292016-06-02 14:46:10 +01002657 }
2658
2659 assembler->Bind(&if_rhsisnotstring);
2660 {
2661 // Check if the {rhs} is a JSReceiver.
Ben Murdoch61f157c2016-09-16 13:49:30 +01002662 Label if_rhsisreceiver(assembler),
Ben Murdochda12d292016-06-02 14:46:10 +01002663 if_rhsisnotreceiver(assembler);
2664 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
2665 assembler->Branch(
2666 assembler->Int32LessThanOrEqual(
2667 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
2668 rhs_instance_type),
2669 &if_rhsisreceiver, &if_rhsisnotreceiver);
2670
2671 assembler->Bind(&if_rhsisreceiver);
2672 {
2673 // The {lhs} is a Primitive and the {rhs} is a JSReceiver.
2674 // Swapping {lhs} and {rhs} is not observable and doesn't
2675 // matter for the result, so we can just swap them and use
2676 // the JSReceiver handling below (for {lhs} being a
2677 // JSReceiver).
2678 var_lhs.Bind(rhs);
2679 var_rhs.Bind(lhs);
2680 assembler->Goto(&loop);
2681 }
2682
2683 assembler->Bind(&if_rhsisnotreceiver);
2684 {
2685 // Check if {rhs} is a Boolean.
2686 Label if_rhsisboolean(assembler),
2687 if_rhsisnotboolean(assembler);
2688 Node* boolean_map = assembler->BooleanMapConstant();
2689 assembler->Branch(assembler->WordEqual(rhs_map, boolean_map),
2690 &if_rhsisboolean, &if_rhsisnotboolean);
2691
2692 assembler->Bind(&if_rhsisboolean);
2693 {
2694 // The {rhs} is a Boolean, convert it to a Smi first.
2695 var_rhs.Bind(assembler->LoadObjectField(
2696 rhs, Oddball::kToNumberOffset));
2697 assembler->Goto(&loop);
2698 }
2699
2700 assembler->Bind(&if_rhsisnotboolean);
2701 assembler->Goto(&if_notequal);
2702 }
2703 }
2704 }
2705 }
2706
2707 assembler->Bind(&if_lhsisoddball);
2708 {
2709 // The {lhs} is an Oddball and {rhs} is some other HeapObject.
2710 Label if_lhsisboolean(assembler), if_lhsisnotboolean(assembler);
2711 Node* boolean_map = assembler->BooleanMapConstant();
2712 assembler->Branch(assembler->WordEqual(lhs_map, boolean_map),
2713 &if_lhsisboolean, &if_lhsisnotboolean);
2714
2715 assembler->Bind(&if_lhsisboolean);
2716 {
2717 // The {lhs} is a Boolean, check if {rhs} is also a Boolean.
2718 Label if_rhsisboolean(assembler), if_rhsisnotboolean(assembler);
2719 assembler->Branch(assembler->WordEqual(rhs_map, boolean_map),
2720 &if_rhsisboolean, &if_rhsisnotboolean);
2721
2722 assembler->Bind(&if_rhsisboolean);
2723 {
2724 // Both {lhs} and {rhs} are distinct Boolean values.
2725 assembler->Goto(&if_notequal);
2726 }
2727
2728 assembler->Bind(&if_rhsisnotboolean);
2729 {
2730 // Convert the {lhs} to a Number first.
2731 var_lhs.Bind(
2732 assembler->LoadObjectField(lhs, Oddball::kToNumberOffset));
2733 assembler->Goto(&loop);
2734 }
2735 }
2736
2737 assembler->Bind(&if_lhsisnotboolean);
2738 {
2739 // The {lhs} is either Null or Undefined; check if the {rhs} is
2740 // undetectable (i.e. either also Null or Undefined or some
2741 // undetectable JSReceiver).
2742 Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map);
2743 assembler->BranchIfWord32Equal(
2744 assembler->Word32And(
2745 rhs_bitfield,
2746 assembler->Int32Constant(1 << Map::kIsUndetectable)),
2747 assembler->Int32Constant(0), &if_notequal, &if_equal);
2748 }
2749 }
2750
2751 assembler->Bind(&if_lhsissymbol);
2752 {
2753 // Check if the {rhs} is a JSReceiver.
Ben Murdoch61f157c2016-09-16 13:49:30 +01002754 Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler);
Ben Murdochda12d292016-06-02 14:46:10 +01002755 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
2756 assembler->Branch(
2757 assembler->Int32LessThanOrEqual(
2758 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
2759 rhs_instance_type),
2760 &if_rhsisreceiver, &if_rhsisnotreceiver);
2761
2762 assembler->Bind(&if_rhsisreceiver);
2763 {
2764 // The {lhs} is a Primitive and the {rhs} is a JSReceiver.
2765 // Swapping {lhs} and {rhs} is not observable and doesn't
2766 // matter for the result, so we can just swap them and use
2767 // the JSReceiver handling below (for {lhs} being a JSReceiver).
2768 var_lhs.Bind(rhs);
2769 var_rhs.Bind(lhs);
2770 assembler->Goto(&loop);
2771 }
2772
2773 assembler->Bind(&if_rhsisnotreceiver);
2774 {
2775 // The {rhs} is not a JSReceiver and also not the same Symbol
2776 // as the {lhs}, so this is equality check is considered false.
2777 assembler->Goto(&if_notequal);
2778 }
2779 }
2780
2781 assembler->Bind(&if_lhsissimd128value);
2782 {
2783 // Check if the {rhs} is also a Simd128Value.
2784 Label if_rhsissimd128value(assembler),
2785 if_rhsisnotsimd128value(assembler);
2786 assembler->Branch(
2787 assembler->Word32Equal(lhs_instance_type, rhs_instance_type),
2788 &if_rhsissimd128value, &if_rhsisnotsimd128value);
2789
2790 assembler->Bind(&if_rhsissimd128value);
2791 {
2792 // Both {lhs} and {rhs} is a Simd128Value.
2793 GenerateEqual_Simd128Value_HeapObject(assembler, lhs, lhs_map,
2794 rhs, rhs_map, &if_equal,
2795 &if_notequal);
2796 }
2797
2798 assembler->Bind(&if_rhsisnotsimd128value);
2799 {
2800 // Check if the {rhs} is a JSReceiver.
Ben Murdoch61f157c2016-09-16 13:49:30 +01002801 Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler);
Ben Murdochda12d292016-06-02 14:46:10 +01002802 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
2803 assembler->Branch(
2804 assembler->Int32LessThanOrEqual(
2805 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
2806 rhs_instance_type),
2807 &if_rhsisreceiver, &if_rhsisnotreceiver);
2808
2809 assembler->Bind(&if_rhsisreceiver);
2810 {
2811 // The {lhs} is a Primitive and the {rhs} is a JSReceiver.
2812 // Swapping {lhs} and {rhs} is not observable and doesn't
2813 // matter for the result, so we can just swap them and use
2814 // the JSReceiver handling below (for {lhs} being a JSReceiver).
2815 var_lhs.Bind(rhs);
2816 var_rhs.Bind(lhs);
2817 assembler->Goto(&loop);
2818 }
2819
2820 assembler->Bind(&if_rhsisnotreceiver);
2821 {
2822 // The {rhs} is some other Primitive.
2823 assembler->Goto(&if_notequal);
2824 }
2825 }
2826 }
2827
2828 assembler->Bind(&if_lhsisreceiver);
2829 {
2830 // Check if the {rhs} is also a JSReceiver.
2831 Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler);
2832 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
2833 assembler->Branch(
2834 assembler->Int32LessThanOrEqual(
2835 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
2836 rhs_instance_type),
2837 &if_rhsisreceiver, &if_rhsisnotreceiver);
2838
2839 assembler->Bind(&if_rhsisreceiver);
2840 {
2841 // Both {lhs} and {rhs} are different JSReceiver references, so
2842 // this cannot be considered equal.
2843 assembler->Goto(&if_notequal);
2844 }
2845
2846 assembler->Bind(&if_rhsisnotreceiver);
2847 {
2848 // Check if {rhs} is Null or Undefined (an undetectable check
2849 // is sufficient here, since we already know that {rhs} is not
2850 // a JSReceiver).
2851 Label if_rhsisundetectable(assembler),
2852 if_rhsisnotundetectable(assembler, Label::kDeferred);
2853 Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map);
2854 assembler->BranchIfWord32Equal(
2855 assembler->Word32And(
2856 rhs_bitfield,
2857 assembler->Int32Constant(1 << Map::kIsUndetectable)),
2858 assembler->Int32Constant(0), &if_rhsisnotundetectable,
2859 &if_rhsisundetectable);
2860
2861 assembler->Bind(&if_rhsisundetectable);
2862 {
2863 // Check if {lhs} is an undetectable JSReceiver.
2864 Node* lhs_bitfield = assembler->LoadMapBitField(lhs_map);
2865 assembler->BranchIfWord32Equal(
2866 assembler->Word32And(
2867 lhs_bitfield,
2868 assembler->Int32Constant(1 << Map::kIsUndetectable)),
2869 assembler->Int32Constant(0), &if_notequal, &if_equal);
2870 }
2871
2872 assembler->Bind(&if_rhsisnotundetectable);
2873 {
2874 // The {rhs} is some Primitive different from Null and
2875 // Undefined, need to convert {lhs} to Primitive first.
2876 // TODO(bmeurer): Hook up ToPrimitiveStub here once it exists.
2877 var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
2878 context, lhs));
2879 assembler->Goto(&loop);
2880 }
2881 }
2882 }
2883 }
2884 }
2885 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01002886
2887 assembler->Bind(&do_rhsstringtonumber);
2888 {
2889 Callable callable = CodeFactory::StringToNumber(assembler->isolate());
2890 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
2891 assembler->Goto(&loop);
2892 }
Ben Murdochda12d292016-06-02 14:46:10 +01002893 }
2894
2895 assembler->Bind(&do_fcmp);
2896 {
2897 // Load the {lhs} and {rhs} floating point values.
2898 Node* lhs = var_fcmp_lhs.value();
2899 Node* rhs = var_fcmp_rhs.value();
2900
2901 // Perform a fast floating point comparison.
2902 assembler->BranchIfFloat64Equal(lhs, rhs, &if_equal, &if_notequal);
2903 }
2904
2905 assembler->Bind(&if_equal);
Ben Murdoch61f157c2016-09-16 13:49:30 +01002906 {
2907 result.Bind(assembler->BooleanConstant(mode == kDontNegateResult));
2908 assembler->Goto(&end);
2909 }
Ben Murdochda12d292016-06-02 14:46:10 +01002910
2911 assembler->Bind(&if_notequal);
Ben Murdoch61f157c2016-09-16 13:49:30 +01002912 {
2913 result.Bind(assembler->BooleanConstant(mode == kNegateResult));
2914 assembler->Goto(&end);
2915 }
2916
2917 assembler->Bind(&end);
2918 return result.value();
Ben Murdochda12d292016-06-02 14:46:10 +01002919}
2920
Ben Murdoch61f157c2016-09-16 13:49:30 +01002921compiler::Node* GenerateStrictEqual(CodeStubAssembler* assembler,
2922 ResultMode mode, compiler::Node* lhs,
2923 compiler::Node* rhs,
2924 compiler::Node* context) {
Ben Murdochda12d292016-06-02 14:46:10 +01002925 // Here's pseudo-code for the algorithm below in case of kDontNegateResult
2926 // mode; for kNegateResult mode we properly negate the result.
2927 //
2928 // if (lhs == rhs) {
2929 // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN;
2930 // return true;
2931 // }
2932 // if (!lhs->IsSmi()) {
2933 // if (lhs->IsHeapNumber()) {
2934 // if (rhs->IsSmi()) {
2935 // return Smi::cast(rhs)->value() == HeapNumber::cast(lhs)->value();
2936 // } else if (rhs->IsHeapNumber()) {
2937 // return HeapNumber::cast(rhs)->value() ==
2938 // HeapNumber::cast(lhs)->value();
2939 // } else {
2940 // return false;
2941 // }
2942 // } else {
2943 // if (rhs->IsSmi()) {
2944 // return false;
2945 // } else {
2946 // if (lhs->IsString()) {
2947 // if (rhs->IsString()) {
2948 // return %StringEqual(lhs, rhs);
2949 // } else {
2950 // return false;
2951 // }
2952 // } else if (lhs->IsSimd128()) {
2953 // if (rhs->IsSimd128()) {
2954 // return %StrictEqual(lhs, rhs);
2955 // }
2956 // } else {
2957 // return false;
2958 // }
2959 // }
2960 // }
2961 // } else {
2962 // if (rhs->IsSmi()) {
2963 // return false;
2964 // } else {
2965 // if (rhs->IsHeapNumber()) {
2966 // return Smi::cast(lhs)->value() == HeapNumber::cast(rhs)->value();
2967 // } else {
2968 // return false;
2969 // }
2970 // }
2971 // }
2972
Ben Murdochc5610432016-08-08 18:44:38 +01002973 typedef CodeStubAssembler::Label Label;
Ben Murdoch61f157c2016-09-16 13:49:30 +01002974 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +01002975 typedef compiler::Node Node;
2976
Ben Murdoch61f157c2016-09-16 13:49:30 +01002977 Label if_equal(assembler), if_notequal(assembler), end(assembler);
2978 Variable result(assembler, MachineRepresentation::kTagged);
Ben Murdochda12d292016-06-02 14:46:10 +01002979
2980 // Check if {lhs} and {rhs} refer to the same object.
2981 Label if_same(assembler), if_notsame(assembler);
2982 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
2983
2984 assembler->Bind(&if_same);
2985 {
2986 // The {lhs} and {rhs} reference the exact same value, yet we need special
2987 // treatment for HeapNumber, as NaN is not equal to NaN.
2988 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal);
2989 }
2990
2991 assembler->Bind(&if_notsame);
2992 {
2993 // The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber,
2994 // String and Simd128Value they can still be considered equal.
2995 Node* number_map = assembler->HeapNumberMapConstant();
2996
2997 // Check if {lhs} is a Smi or a HeapObject.
2998 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
2999 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
3000
3001 assembler->Bind(&if_lhsisnotsmi);
3002 {
3003 // Load the map of {lhs}.
3004 Node* lhs_map = assembler->LoadMap(lhs);
3005
3006 // Check if {lhs} is a HeapNumber.
3007 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler);
3008 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
3009 &if_lhsisnumber, &if_lhsisnotnumber);
3010
3011 assembler->Bind(&if_lhsisnumber);
3012 {
3013 // Check if {rhs} is a Smi or a HeapObject.
3014 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
3015 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
3016 &if_rhsisnotsmi);
3017
3018 assembler->Bind(&if_rhsissmi);
3019 {
3020 // Convert {lhs} and {rhs} to floating point values.
3021 Node* lhs_value = assembler->LoadHeapNumberValue(lhs);
3022 Node* rhs_value = assembler->SmiToFloat64(rhs);
3023
3024 // Perform a floating point comparison of {lhs} and {rhs}.
3025 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal,
3026 &if_notequal);
3027 }
3028
3029 assembler->Bind(&if_rhsisnotsmi);
3030 {
3031 // Load the map of {rhs}.
3032 Node* rhs_map = assembler->LoadMap(rhs);
3033
3034 // Check if {rhs} is also a HeapNumber.
3035 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler);
3036 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
3037 &if_rhsisnumber, &if_rhsisnotnumber);
3038
3039 assembler->Bind(&if_rhsisnumber);
3040 {
3041 // Convert {lhs} and {rhs} to floating point values.
3042 Node* lhs_value = assembler->LoadHeapNumberValue(lhs);
3043 Node* rhs_value = assembler->LoadHeapNumberValue(rhs);
3044
3045 // Perform a floating point comparison of {lhs} and {rhs}.
3046 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal,
3047 &if_notequal);
3048 }
3049
3050 assembler->Bind(&if_rhsisnotnumber);
3051 assembler->Goto(&if_notequal);
3052 }
3053 }
3054
3055 assembler->Bind(&if_lhsisnotnumber);
3056 {
3057 // Check if {rhs} is a Smi or a HeapObject.
3058 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
3059 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
3060 &if_rhsisnotsmi);
3061
3062 assembler->Bind(&if_rhsissmi);
3063 assembler->Goto(&if_notequal);
3064
3065 assembler->Bind(&if_rhsisnotsmi);
3066 {
3067 // Load the instance type of {lhs}.
3068 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map);
3069
3070 // Check if {lhs} is a String.
3071 Label if_lhsisstring(assembler), if_lhsisnotstring(assembler);
3072 assembler->Branch(assembler->Int32LessThan(
3073 lhs_instance_type,
3074 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
3075 &if_lhsisstring, &if_lhsisnotstring);
3076
3077 assembler->Bind(&if_lhsisstring);
3078 {
3079 // Load the instance type of {rhs}.
3080 Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
3081
3082 // Check if {rhs} is also a String.
Ben Murdoch61f157c2016-09-16 13:49:30 +01003083 Label if_rhsisstring(assembler, Label::kDeferred),
3084 if_rhsisnotstring(assembler);
Ben Murdochda12d292016-06-02 14:46:10 +01003085 assembler->Branch(assembler->Int32LessThan(
3086 rhs_instance_type, assembler->Int32Constant(
3087 FIRST_NONSTRING_TYPE)),
3088 &if_rhsisstring, &if_rhsisnotstring);
3089
3090 assembler->Bind(&if_rhsisstring);
3091 {
3092 Callable callable =
3093 (mode == kDontNegateResult)
3094 ? CodeFactory::StringEqual(assembler->isolate())
3095 : CodeFactory::StringNotEqual(assembler->isolate());
Ben Murdoch61f157c2016-09-16 13:49:30 +01003096 result.Bind(assembler->CallStub(callable, context, lhs, rhs));
3097 assembler->Goto(&end);
Ben Murdochda12d292016-06-02 14:46:10 +01003098 }
3099
3100 assembler->Bind(&if_rhsisnotstring);
3101 assembler->Goto(&if_notequal);
3102 }
3103
3104 assembler->Bind(&if_lhsisnotstring);
3105 {
3106 // Check if {lhs} is a Simd128Value.
3107 Label if_lhsissimd128value(assembler),
3108 if_lhsisnotsimd128value(assembler);
3109 assembler->Branch(assembler->Word32Equal(
3110 lhs_instance_type,
3111 assembler->Int32Constant(SIMD128_VALUE_TYPE)),
3112 &if_lhsissimd128value, &if_lhsisnotsimd128value);
3113
3114 assembler->Bind(&if_lhsissimd128value);
3115 {
3116 // Load the map of {rhs}.
3117 Node* rhs_map = assembler->LoadMap(rhs);
3118
3119 // Check if {rhs} is also a Simd128Value that is equal to {lhs}.
3120 GenerateEqual_Simd128Value_HeapObject(assembler, lhs, lhs_map,
3121 rhs, rhs_map, &if_equal,
3122 &if_notequal);
3123 }
3124
3125 assembler->Bind(&if_lhsisnotsimd128value);
3126 assembler->Goto(&if_notequal);
3127 }
3128 }
3129 }
3130 }
3131
3132 assembler->Bind(&if_lhsissmi);
3133 {
3134 // We already know that {lhs} and {rhs} are not reference equal, and {lhs}
3135 // is a Smi; so {lhs} and {rhs} can only be strictly equal if {rhs} is a
3136 // HeapNumber with an equal floating point value.
3137
3138 // Check if {rhs} is a Smi or a HeapObject.
3139 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
3140 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
3141 &if_rhsisnotsmi);
3142
3143 assembler->Bind(&if_rhsissmi);
3144 assembler->Goto(&if_notequal);
3145
3146 assembler->Bind(&if_rhsisnotsmi);
3147 {
3148 // Load the map of the {rhs}.
3149 Node* rhs_map = assembler->LoadMap(rhs);
3150
3151 // The {rhs} could be a HeapNumber with the same value as {lhs}.
3152 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler);
3153 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
3154 &if_rhsisnumber, &if_rhsisnotnumber);
3155
3156 assembler->Bind(&if_rhsisnumber);
3157 {
3158 // Convert {lhs} and {rhs} to floating point values.
3159 Node* lhs_value = assembler->SmiToFloat64(lhs);
3160 Node* rhs_value = assembler->LoadHeapNumberValue(rhs);
3161
3162 // Perform a floating point comparison of {lhs} and {rhs}.
3163 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal,
3164 &if_notequal);
3165 }
3166
3167 assembler->Bind(&if_rhsisnotnumber);
3168 assembler->Goto(&if_notequal);
3169 }
3170 }
3171 }
3172
3173 assembler->Bind(&if_equal);
Ben Murdoch61f157c2016-09-16 13:49:30 +01003174 {
3175 result.Bind(assembler->BooleanConstant(mode == kDontNegateResult));
3176 assembler->Goto(&end);
3177 }
Ben Murdochda12d292016-06-02 14:46:10 +01003178
3179 assembler->Bind(&if_notequal);
Ben Murdoch61f157c2016-09-16 13:49:30 +01003180 {
3181 result.Bind(assembler->BooleanConstant(mode == kNegateResult));
3182 assembler->Goto(&end);
3183 }
3184
3185 assembler->Bind(&end);
3186 return result.value();
Ben Murdochda12d292016-06-02 14:46:10 +01003187}
3188
Ben Murdochc5610432016-08-08 18:44:38 +01003189void GenerateStringRelationalComparison(CodeStubAssembler* assembler,
Ben Murdochda12d292016-06-02 14:46:10 +01003190 RelationalComparisonMode mode) {
Ben Murdochc5610432016-08-08 18:44:38 +01003191 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01003192 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +01003193 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +01003194
3195 Node* lhs = assembler->Parameter(0);
3196 Node* rhs = assembler->Parameter(1);
3197 Node* context = assembler->Parameter(2);
3198
3199 Label if_less(assembler), if_equal(assembler), if_greater(assembler);
3200
3201 // Fast check to see if {lhs} and {rhs} refer to the same String object.
3202 Label if_same(assembler), if_notsame(assembler);
3203 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
3204
3205 assembler->Bind(&if_same);
3206 assembler->Goto(&if_equal);
3207
3208 assembler->Bind(&if_notsame);
3209 {
3210 // Load instance types of {lhs} and {rhs}.
3211 Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
3212 Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
3213
3214 // Combine the instance types into a single 16-bit value, so we can check
3215 // both of them at once.
3216 Node* both_instance_types = assembler->Word32Or(
3217 lhs_instance_type,
3218 assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
3219
3220 // Check that both {lhs} and {rhs} are flat one-byte strings.
3221 int const kBothSeqOneByteStringMask =
3222 kStringEncodingMask | kStringRepresentationMask |
3223 ((kStringEncodingMask | kStringRepresentationMask) << 8);
3224 int const kBothSeqOneByteStringTag =
3225 kOneByteStringTag | kSeqStringTag |
3226 ((kOneByteStringTag | kSeqStringTag) << 8);
3227 Label if_bothonebyteseqstrings(assembler),
3228 if_notbothonebyteseqstrings(assembler);
3229 assembler->Branch(assembler->Word32Equal(
3230 assembler->Word32And(both_instance_types,
3231 assembler->Int32Constant(
3232 kBothSeqOneByteStringMask)),
3233 assembler->Int32Constant(kBothSeqOneByteStringTag)),
3234 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
3235
3236 assembler->Bind(&if_bothonebyteseqstrings);
3237 {
3238 // Load the length of {lhs} and {rhs}.
3239 Node* lhs_length = assembler->LoadObjectField(lhs, String::kLengthOffset);
3240 Node* rhs_length = assembler->LoadObjectField(rhs, String::kLengthOffset);
3241
3242 // Determine the minimum length.
3243 Node* length = assembler->SmiMin(lhs_length, rhs_length);
3244
3245 // Compute the effective offset of the first character.
3246 Node* begin = assembler->IntPtrConstant(SeqOneByteString::kHeaderSize -
3247 kHeapObjectTag);
3248
3249 // Compute the first offset after the string from the length.
3250 Node* end = assembler->IntPtrAdd(begin, assembler->SmiUntag(length));
3251
3252 // Loop over the {lhs} and {rhs} strings to see if they are equal.
3253 Variable var_offset(assembler, MachineType::PointerRepresentation());
3254 Label loop(assembler, &var_offset);
3255 var_offset.Bind(begin);
3256 assembler->Goto(&loop);
3257 assembler->Bind(&loop);
3258 {
3259 // Check if {offset} equals {end}.
3260 Node* offset = var_offset.value();
3261 Label if_done(assembler), if_notdone(assembler);
3262 assembler->Branch(assembler->WordEqual(offset, end), &if_done,
3263 &if_notdone);
3264
3265 assembler->Bind(&if_notdone);
3266 {
3267 // Load the next characters from {lhs} and {rhs}.
3268 Node* lhs_value = assembler->Load(MachineType::Uint8(), lhs, offset);
3269 Node* rhs_value = assembler->Load(MachineType::Uint8(), rhs, offset);
3270
3271 // Check if the characters match.
3272 Label if_valueissame(assembler), if_valueisnotsame(assembler);
3273 assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
3274 &if_valueissame, &if_valueisnotsame);
3275
3276 assembler->Bind(&if_valueissame);
3277 {
3278 // Advance to next character.
3279 var_offset.Bind(
3280 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
3281 }
3282 assembler->Goto(&loop);
3283
3284 assembler->Bind(&if_valueisnotsame);
3285 assembler->BranchIf(assembler->Uint32LessThan(lhs_value, rhs_value),
3286 &if_less, &if_greater);
3287 }
3288
3289 assembler->Bind(&if_done);
3290 {
3291 // All characters up to the min length are equal, decide based on
3292 // string length.
3293 Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
3294 assembler->Branch(assembler->SmiEqual(lhs_length, rhs_length),
3295 &if_lengthisequal, &if_lengthisnotequal);
3296
3297 assembler->Bind(&if_lengthisequal);
3298 assembler->Goto(&if_equal);
3299
3300 assembler->Bind(&if_lengthisnotequal);
3301 assembler->BranchIfSmiLessThan(lhs_length, rhs_length, &if_less,
3302 &if_greater);
3303 }
3304 }
3305 }
3306
3307 assembler->Bind(&if_notbothonebyteseqstrings);
3308 {
3309 // TODO(bmeurer): Add fast case support for flattened cons strings;
3310 // also add support for two byte string relational comparisons.
3311 switch (mode) {
3312 case kLessThan:
3313 assembler->TailCallRuntime(Runtime::kStringLessThan, context, lhs,
3314 rhs);
3315 break;
3316 case kLessThanOrEqual:
3317 assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual, context,
3318 lhs, rhs);
3319 break;
3320 case kGreaterThan:
3321 assembler->TailCallRuntime(Runtime::kStringGreaterThan, context, lhs,
3322 rhs);
3323 break;
3324 case kGreaterThanOrEqual:
3325 assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual,
3326 context, lhs, rhs);
3327 break;
3328 }
3329 }
3330 }
3331
3332 assembler->Bind(&if_less);
3333 switch (mode) {
3334 case kLessThan:
3335 case kLessThanOrEqual:
3336 assembler->Return(assembler->BooleanConstant(true));
3337 break;
3338
3339 case kGreaterThan:
3340 case kGreaterThanOrEqual:
3341 assembler->Return(assembler->BooleanConstant(false));
3342 break;
3343 }
3344
3345 assembler->Bind(&if_equal);
3346 switch (mode) {
3347 case kLessThan:
3348 case kGreaterThan:
3349 assembler->Return(assembler->BooleanConstant(false));
3350 break;
3351
3352 case kLessThanOrEqual:
3353 case kGreaterThanOrEqual:
3354 assembler->Return(assembler->BooleanConstant(true));
3355 break;
3356 }
3357
3358 assembler->Bind(&if_greater);
3359 switch (mode) {
3360 case kLessThan:
3361 case kLessThanOrEqual:
3362 assembler->Return(assembler->BooleanConstant(false));
3363 break;
3364
3365 case kGreaterThan:
3366 case kGreaterThanOrEqual:
3367 assembler->Return(assembler->BooleanConstant(true));
3368 break;
3369 }
3370}
3371
Ben Murdochc5610432016-08-08 18:44:38 +01003372void GenerateStringEqual(CodeStubAssembler* assembler, ResultMode mode) {
Ben Murdochda12d292016-06-02 14:46:10 +01003373 // Here's pseudo-code for the algorithm below in case of kDontNegateResult
3374 // mode; for kNegateResult mode we properly negate the result.
3375 //
3376 // if (lhs == rhs) return true;
3377 // if (lhs->length() != rhs->length()) return false;
3378 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) {
3379 // return false;
3380 // }
3381 // if (lhs->IsSeqOneByteString() && rhs->IsSeqOneByteString()) {
3382 // for (i = 0; i != lhs->length(); ++i) {
3383 // if (lhs[i] != rhs[i]) return false;
3384 // }
3385 // return true;
3386 // }
3387 // return %StringEqual(lhs, rhs);
3388
Ben Murdochc5610432016-08-08 18:44:38 +01003389 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01003390 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +01003391 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +01003392
3393 Node* lhs = assembler->Parameter(0);
3394 Node* rhs = assembler->Parameter(1);
3395 Node* context = assembler->Parameter(2);
3396
3397 Label if_equal(assembler), if_notequal(assembler);
3398
3399 // Fast check to see if {lhs} and {rhs} refer to the same String object.
3400 Label if_same(assembler), if_notsame(assembler);
3401 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
3402
3403 assembler->Bind(&if_same);
3404 assembler->Goto(&if_equal);
3405
3406 assembler->Bind(&if_notsame);
3407 {
3408 // The {lhs} and {rhs} don't refer to the exact same String object.
3409
3410 // Load the length of {lhs} and {rhs}.
3411 Node* lhs_length = assembler->LoadObjectField(lhs, String::kLengthOffset);
3412 Node* rhs_length = assembler->LoadObjectField(rhs, String::kLengthOffset);
3413
3414 // Check if the lengths of {lhs} and {rhs} are equal.
3415 Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
3416 assembler->Branch(assembler->WordEqual(lhs_length, rhs_length),
3417 &if_lengthisequal, &if_lengthisnotequal);
3418
3419 assembler->Bind(&if_lengthisequal);
3420 {
3421 // Load instance types of {lhs} and {rhs}.
3422 Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
3423 Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
3424
3425 // Combine the instance types into a single 16-bit value, so we can check
3426 // both of them at once.
3427 Node* both_instance_types = assembler->Word32Or(
3428 lhs_instance_type,
3429 assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
3430
3431 // Check if both {lhs} and {rhs} are internalized.
3432 int const kBothInternalizedMask =
3433 kIsNotInternalizedMask | (kIsNotInternalizedMask << 8);
3434 int const kBothInternalizedTag =
3435 kInternalizedTag | (kInternalizedTag << 8);
3436 Label if_bothinternalized(assembler), if_notbothinternalized(assembler);
3437 assembler->Branch(assembler->Word32Equal(
3438 assembler->Word32And(both_instance_types,
3439 assembler->Int32Constant(
3440 kBothInternalizedMask)),
3441 assembler->Int32Constant(kBothInternalizedTag)),
3442 &if_bothinternalized, &if_notbothinternalized);
3443
3444 assembler->Bind(&if_bothinternalized);
3445 {
3446 // Fast negative check for internalized-to-internalized equality.
3447 assembler->Goto(&if_notequal);
3448 }
3449
3450 assembler->Bind(&if_notbothinternalized);
3451 {
3452 // Check that both {lhs} and {rhs} are flat one-byte strings.
3453 int const kBothSeqOneByteStringMask =
3454 kStringEncodingMask | kStringRepresentationMask |
3455 ((kStringEncodingMask | kStringRepresentationMask) << 8);
3456 int const kBothSeqOneByteStringTag =
3457 kOneByteStringTag | kSeqStringTag |
3458 ((kOneByteStringTag | kSeqStringTag) << 8);
3459 Label if_bothonebyteseqstrings(assembler),
3460 if_notbothonebyteseqstrings(assembler);
3461 assembler->Branch(
3462 assembler->Word32Equal(
3463 assembler->Word32And(
3464 both_instance_types,
3465 assembler->Int32Constant(kBothSeqOneByteStringMask)),
3466 assembler->Int32Constant(kBothSeqOneByteStringTag)),
3467 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
3468
3469 assembler->Bind(&if_bothonebyteseqstrings);
3470 {
3471 // Compute the effective offset of the first character.
3472 Node* begin = assembler->IntPtrConstant(
3473 SeqOneByteString::kHeaderSize - kHeapObjectTag);
3474
3475 // Compute the first offset after the string from the length.
3476 Node* end =
3477 assembler->IntPtrAdd(begin, assembler->SmiUntag(lhs_length));
3478
3479 // Loop over the {lhs} and {rhs} strings to see if they are equal.
3480 Variable var_offset(assembler, MachineType::PointerRepresentation());
3481 Label loop(assembler, &var_offset);
3482 var_offset.Bind(begin);
3483 assembler->Goto(&loop);
3484 assembler->Bind(&loop);
3485 {
3486 // Check if {offset} equals {end}.
3487 Node* offset = var_offset.value();
3488 Label if_done(assembler), if_notdone(assembler);
3489 assembler->Branch(assembler->WordEqual(offset, end), &if_done,
3490 &if_notdone);
3491
3492 assembler->Bind(&if_notdone);
3493 {
3494 // Load the next characters from {lhs} and {rhs}.
3495 Node* lhs_value =
3496 assembler->Load(MachineType::Uint8(), lhs, offset);
3497 Node* rhs_value =
3498 assembler->Load(MachineType::Uint8(), rhs, offset);
3499
3500 // Check if the characters match.
3501 Label if_valueissame(assembler), if_valueisnotsame(assembler);
3502 assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
3503 &if_valueissame, &if_valueisnotsame);
3504
3505 assembler->Bind(&if_valueissame);
3506 {
3507 // Advance to next character.
3508 var_offset.Bind(
3509 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
3510 }
3511 assembler->Goto(&loop);
3512
3513 assembler->Bind(&if_valueisnotsame);
3514 assembler->Goto(&if_notequal);
3515 }
3516
3517 assembler->Bind(&if_done);
3518 assembler->Goto(&if_equal);
3519 }
3520 }
3521
3522 assembler->Bind(&if_notbothonebyteseqstrings);
3523 {
3524 // TODO(bmeurer): Add fast case support for flattened cons strings;
3525 // also add support for two byte string equality checks.
3526 Runtime::FunctionId function_id = (mode == kDontNegateResult)
3527 ? Runtime::kStringEqual
3528 : Runtime::kStringNotEqual;
3529 assembler->TailCallRuntime(function_id, context, lhs, rhs);
3530 }
3531 }
3532 }
3533
3534 assembler->Bind(&if_lengthisnotequal);
3535 {
3536 // Mismatch in length of {lhs} and {rhs}, cannot be equal.
3537 assembler->Goto(&if_notequal);
3538 }
3539 }
3540
3541 assembler->Bind(&if_equal);
3542 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult));
3543
3544 assembler->Bind(&if_notequal);
3545 assembler->Return(assembler->BooleanConstant(mode == kNegateResult));
3546}
3547
3548} // namespace
3549
Ben Murdochc5610432016-08-08 18:44:38 +01003550void LoadApiGetterStub::GenerateAssembly(CodeStubAssembler* assembler) const {
3551 typedef compiler::Node Node;
3552 Node* context = assembler->Parameter(3);
3553 Node* receiver = assembler->Parameter(0);
3554 // For now we only support receiver_is_holder.
3555 DCHECK(receiver_is_holder());
3556 Node* holder = receiver;
3557 Node* map = assembler->LoadMap(receiver);
3558 Node* descriptors = assembler->LoadMapDescriptors(map);
3559 Node* offset =
3560 assembler->Int32Constant(DescriptorArray::ToValueIndex(index()));
3561 Node* callback = assembler->LoadFixedArrayElement(descriptors, offset);
3562 assembler->TailCallStub(CodeFactory::ApiGetter(isolate()), context, receiver,
3563 holder, callback);
3564}
3565
Ben Murdoch61f157c2016-09-16 13:49:30 +01003566// static
3567compiler::Node* LessThanStub::Generate(CodeStubAssembler* assembler,
3568 compiler::Node* lhs, compiler::Node* rhs,
3569 compiler::Node* context) {
3570 return GenerateAbstractRelationalComparison(assembler, kLessThan, lhs, rhs,
3571 context);
Ben Murdochda12d292016-06-02 14:46:10 +01003572}
3573
Ben Murdoch61f157c2016-09-16 13:49:30 +01003574// static
3575compiler::Node* LessThanOrEqualStub::Generate(CodeStubAssembler* assembler,
3576 compiler::Node* lhs,
3577 compiler::Node* rhs,
3578 compiler::Node* context) {
3579 return GenerateAbstractRelationalComparison(assembler, kLessThanOrEqual, lhs,
3580 rhs, context);
Ben Murdochda12d292016-06-02 14:46:10 +01003581}
3582
Ben Murdoch61f157c2016-09-16 13:49:30 +01003583// static
3584compiler::Node* GreaterThanStub::Generate(CodeStubAssembler* assembler,
3585 compiler::Node* lhs,
3586 compiler::Node* rhs,
3587 compiler::Node* context) {
3588 return GenerateAbstractRelationalComparison(assembler, kGreaterThan, lhs, rhs,
3589 context);
Ben Murdochda12d292016-06-02 14:46:10 +01003590}
3591
Ben Murdoch61f157c2016-09-16 13:49:30 +01003592// static
3593compiler::Node* GreaterThanOrEqualStub::Generate(CodeStubAssembler* assembler,
3594 compiler::Node* lhs,
3595 compiler::Node* rhs,
3596 compiler::Node* context) {
3597 return GenerateAbstractRelationalComparison(assembler, kGreaterThanOrEqual,
3598 lhs, rhs, context);
Ben Murdochda12d292016-06-02 14:46:10 +01003599}
3600
Ben Murdoch61f157c2016-09-16 13:49:30 +01003601// static
3602compiler::Node* EqualStub::Generate(CodeStubAssembler* assembler,
3603 compiler::Node* lhs, compiler::Node* rhs,
3604 compiler::Node* context) {
3605 return GenerateEqual(assembler, kDontNegateResult, lhs, rhs, context);
Ben Murdochda12d292016-06-02 14:46:10 +01003606}
3607
Ben Murdoch61f157c2016-09-16 13:49:30 +01003608// static
3609compiler::Node* NotEqualStub::Generate(CodeStubAssembler* assembler,
3610 compiler::Node* lhs, compiler::Node* rhs,
3611 compiler::Node* context) {
3612 return GenerateEqual(assembler, kNegateResult, lhs, rhs, context);
Ben Murdochda12d292016-06-02 14:46:10 +01003613}
3614
Ben Murdoch61f157c2016-09-16 13:49:30 +01003615// static
3616compiler::Node* StrictEqualStub::Generate(CodeStubAssembler* assembler,
3617 compiler::Node* lhs,
3618 compiler::Node* rhs,
3619 compiler::Node* context) {
3620 return GenerateStrictEqual(assembler, kDontNegateResult, lhs, rhs, context);
Ben Murdochda12d292016-06-02 14:46:10 +01003621}
3622
Ben Murdoch61f157c2016-09-16 13:49:30 +01003623// static
3624compiler::Node* StrictNotEqualStub::Generate(CodeStubAssembler* assembler,
3625 compiler::Node* lhs,
3626 compiler::Node* rhs,
3627 compiler::Node* context) {
3628 return GenerateStrictEqual(assembler, kNegateResult, lhs, rhs, context);
Ben Murdochda12d292016-06-02 14:46:10 +01003629}
3630
Ben Murdochc5610432016-08-08 18:44:38 +01003631void StringEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003632 GenerateStringEqual(assembler, kDontNegateResult);
3633}
3634
Ben Murdochc5610432016-08-08 18:44:38 +01003635void StringNotEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003636 GenerateStringEqual(assembler, kNegateResult);
3637}
3638
Ben Murdochc5610432016-08-08 18:44:38 +01003639void StringLessThanStub::GenerateAssembly(CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003640 GenerateStringRelationalComparison(assembler, kLessThan);
3641}
3642
3643void StringLessThanOrEqualStub::GenerateAssembly(
Ben Murdochc5610432016-08-08 18:44:38 +01003644 CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003645 GenerateStringRelationalComparison(assembler, kLessThanOrEqual);
3646}
3647
3648void StringGreaterThanStub::GenerateAssembly(
Ben Murdochc5610432016-08-08 18:44:38 +01003649 CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003650 GenerateStringRelationalComparison(assembler, kGreaterThan);
3651}
3652
3653void StringGreaterThanOrEqualStub::GenerateAssembly(
Ben Murdochc5610432016-08-08 18:44:38 +01003654 CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003655 GenerateStringRelationalComparison(assembler, kGreaterThanOrEqual);
3656}
3657
Ben Murdochc5610432016-08-08 18:44:38 +01003658void ToLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const {
3659 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01003660 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +01003661 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +01003662
3663 Node* context = assembler->Parameter(1);
3664
3665 // We might need to loop once for ToNumber conversion.
3666 Variable var_len(assembler, MachineRepresentation::kTagged);
3667 Label loop(assembler, &var_len);
3668 var_len.Bind(assembler->Parameter(0));
3669 assembler->Goto(&loop);
3670 assembler->Bind(&loop);
3671 {
3672 // Shared entry points.
3673 Label return_len(assembler),
3674 return_two53minus1(assembler, Label::kDeferred),
3675 return_zero(assembler, Label::kDeferred);
3676
3677 // Load the current {len} value.
3678 Node* len = var_len.value();
3679
3680 // Check if {len} is a positive Smi.
3681 assembler->GotoIf(assembler->WordIsPositiveSmi(len), &return_len);
3682
3683 // Check if {len} is a (negative) Smi.
3684 assembler->GotoIf(assembler->WordIsSmi(len), &return_zero);
3685
3686 // Check if {len} is a HeapNumber.
3687 Label if_lenisheapnumber(assembler),
3688 if_lenisnotheapnumber(assembler, Label::kDeferred);
3689 assembler->Branch(assembler->WordEqual(assembler->LoadMap(len),
3690 assembler->HeapNumberMapConstant()),
3691 &if_lenisheapnumber, &if_lenisnotheapnumber);
3692
3693 assembler->Bind(&if_lenisheapnumber);
3694 {
3695 // Load the floating-point value of {len}.
3696 Node* len_value = assembler->LoadHeapNumberValue(len);
3697
3698 // Check if {len} is not greater than zero.
3699 assembler->GotoUnless(assembler->Float64GreaterThan(
3700 len_value, assembler->Float64Constant(0.0)),
3701 &return_zero);
3702
3703 // Check if {len} is greater than or equal to 2^53-1.
3704 assembler->GotoIf(
3705 assembler->Float64GreaterThanOrEqual(
3706 len_value, assembler->Float64Constant(kMaxSafeInteger)),
3707 &return_two53minus1);
3708
3709 // Round the {len} towards -Infinity.
3710 Node* value = assembler->Float64Floor(len_value);
3711 Node* result = assembler->ChangeFloat64ToTagged(value);
3712 assembler->Return(result);
3713 }
3714
3715 assembler->Bind(&if_lenisnotheapnumber);
3716 {
3717 // Need to convert {len} to a Number first.
3718 Callable callable = CodeFactory::NonNumberToNumber(assembler->isolate());
3719 var_len.Bind(assembler->CallStub(callable, context, len));
3720 assembler->Goto(&loop);
3721 }
3722
3723 assembler->Bind(&return_len);
3724 assembler->Return(var_len.value());
3725
3726 assembler->Bind(&return_two53minus1);
3727 assembler->Return(assembler->NumberConstant(kMaxSafeInteger));
3728
3729 assembler->Bind(&return_zero);
3730 assembler->Return(assembler->SmiConstant(Smi::FromInt(0)));
3731 }
3732}
3733
Ben Murdoch61f157c2016-09-16 13:49:30 +01003734// static
3735compiler::Node* ToBooleanStub::Generate(CodeStubAssembler* assembler,
3736 compiler::Node* value,
3737 compiler::Node* context) {
Ben Murdochda12d292016-06-02 14:46:10 +01003738 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +01003739 typedef CodeStubAssembler::Label Label;
Ben Murdoch61f157c2016-09-16 13:49:30 +01003740 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +01003741
Ben Murdoch61f157c2016-09-16 13:49:30 +01003742 Variable result(assembler, MachineRepresentation::kTagged);
Ben Murdochc5610432016-08-08 18:44:38 +01003743 Label if_valueissmi(assembler), if_valueisnotsmi(assembler),
Ben Murdoch61f157c2016-09-16 13:49:30 +01003744 return_true(assembler), return_false(assembler), end(assembler);
Ben Murdochda12d292016-06-02 14:46:10 +01003745
3746 // Check if {value} is a Smi or a HeapObject.
3747 assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi,
3748 &if_valueisnotsmi);
3749
3750 assembler->Bind(&if_valueissmi);
3751 {
3752 // The {value} is a Smi, only need to check against zero.
Ben Murdochda12d292016-06-02 14:46:10 +01003753 assembler->Branch(assembler->SmiEqual(value, assembler->SmiConstant(0)),
Ben Murdochc5610432016-08-08 18:44:38 +01003754 &return_false, &return_true);
Ben Murdochda12d292016-06-02 14:46:10 +01003755 }
3756
3757 assembler->Bind(&if_valueisnotsmi);
3758 {
Ben Murdochc5610432016-08-08 18:44:38 +01003759 Label if_valueisstring(assembler), if_valueisnotstring(assembler),
3760 if_valueisheapnumber(assembler), if_valueisoddball(assembler),
3761 if_valueisother(assembler);
Ben Murdochda12d292016-06-02 14:46:10 +01003762
3763 // The {value} is a HeapObject, load its map.
3764 Node* value_map = assembler->LoadMap(value);
3765
3766 // Load the {value}s instance type.
3767 Node* value_instance_type = assembler->Load(
3768 MachineType::Uint8(), value_map,
3769 assembler->IntPtrConstant(Map::kInstanceTypeOffset - kHeapObjectTag));
3770
3771 // Dispatch based on the instance type; we distinguish all String instance
3772 // types, the HeapNumber type and the Oddball type.
Ben Murdochc5610432016-08-08 18:44:38 +01003773 assembler->Branch(assembler->Int32LessThan(
3774 value_instance_type,
3775 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
3776 &if_valueisstring, &if_valueisnotstring);
3777 assembler->Bind(&if_valueisnotstring);
3778 size_t const kNumCases = 2;
Ben Murdochda12d292016-06-02 14:46:10 +01003779 Label* case_labels[kNumCases];
3780 int32_t case_values[kNumCases];
Ben Murdochc5610432016-08-08 18:44:38 +01003781 case_labels[0] = &if_valueisheapnumber;
3782 case_values[0] = HEAP_NUMBER_TYPE;
3783 case_labels[1] = &if_valueisoddball;
3784 case_values[1] = ODDBALL_TYPE;
Ben Murdochda12d292016-06-02 14:46:10 +01003785 assembler->Switch(value_instance_type, &if_valueisother, case_values,
3786 case_labels, arraysize(case_values));
Ben Murdochda12d292016-06-02 14:46:10 +01003787
3788 assembler->Bind(&if_valueisstring);
3789 {
3790 // Load the string length field of the {value}.
3791 Node* value_length =
3792 assembler->LoadObjectField(value, String::kLengthOffset);
3793
3794 // Check if the {value} is the empty string.
Ben Murdochda12d292016-06-02 14:46:10 +01003795 assembler->Branch(
3796 assembler->SmiEqual(value_length, assembler->SmiConstant(0)),
Ben Murdochc5610432016-08-08 18:44:38 +01003797 &return_false, &return_true);
Ben Murdochda12d292016-06-02 14:46:10 +01003798 }
3799
3800 assembler->Bind(&if_valueisheapnumber);
3801 {
3802 Node* value_value = assembler->Load(
3803 MachineType::Float64(), value,
3804 assembler->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag));
3805
Ben Murdochc5610432016-08-08 18:44:38 +01003806 Label if_valueisnotpositive(assembler);
Ben Murdochda12d292016-06-02 14:46:10 +01003807 assembler->Branch(assembler->Float64LessThan(
3808 assembler->Float64Constant(0.0), value_value),
Ben Murdochc5610432016-08-08 18:44:38 +01003809 &return_true, &if_valueisnotpositive);
Ben Murdochda12d292016-06-02 14:46:10 +01003810
3811 assembler->Bind(&if_valueisnotpositive);
3812 assembler->Branch(assembler->Float64LessThan(
3813 value_value, assembler->Float64Constant(0.0)),
Ben Murdochc5610432016-08-08 18:44:38 +01003814 &return_true, &return_false);
Ben Murdochda12d292016-06-02 14:46:10 +01003815 }
3816
3817 assembler->Bind(&if_valueisoddball);
3818 {
3819 // The {value} is an Oddball, and every Oddball knows its boolean value.
3820 Node* value_toboolean =
3821 assembler->LoadObjectField(value, Oddball::kToBooleanOffset);
Ben Murdoch61f157c2016-09-16 13:49:30 +01003822 result.Bind(value_toboolean);
3823 assembler->Goto(&end);
Ben Murdochda12d292016-06-02 14:46:10 +01003824 }
3825
3826 assembler->Bind(&if_valueisother);
3827 {
3828 Node* value_map_bitfield = assembler->Load(
3829 MachineType::Uint8(), value_map,
3830 assembler->IntPtrConstant(Map::kBitFieldOffset - kHeapObjectTag));
3831 Node* value_map_undetectable = assembler->Word32And(
3832 value_map_bitfield,
3833 assembler->Int32Constant(1 << Map::kIsUndetectable));
3834
3835 // Check if the {value} is undetectable.
Ben Murdochda12d292016-06-02 14:46:10 +01003836 assembler->Branch(assembler->Word32Equal(value_map_undetectable,
3837 assembler->Int32Constant(0)),
Ben Murdochc5610432016-08-08 18:44:38 +01003838 &return_true, &return_false);
Ben Murdochda12d292016-06-02 14:46:10 +01003839 }
3840 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01003841
Ben Murdochc5610432016-08-08 18:44:38 +01003842 assembler->Bind(&return_false);
Ben Murdoch61f157c2016-09-16 13:49:30 +01003843 {
3844 result.Bind(assembler->BooleanConstant(false));
3845 assembler->Goto(&end);
3846 }
Ben Murdochc5610432016-08-08 18:44:38 +01003847
3848 assembler->Bind(&return_true);
Ben Murdoch61f157c2016-09-16 13:49:30 +01003849 {
3850 result.Bind(assembler->BooleanConstant(true));
3851 assembler->Goto(&end);
3852 }
3853
3854 assembler->Bind(&end);
3855 return result.value();
Ben Murdochda12d292016-06-02 14:46:10 +01003856}
3857
Ben Murdochc5610432016-08-08 18:44:38 +01003858void ToIntegerStub::GenerateAssembly(CodeStubAssembler* assembler) const {
3859 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01003860 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +01003861 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +01003862
3863 Node* context = assembler->Parameter(1);
3864
3865 // We might need to loop once for ToNumber conversion.
3866 Variable var_arg(assembler, MachineRepresentation::kTagged);
3867 Label loop(assembler, &var_arg);
3868 var_arg.Bind(assembler->Parameter(0));
3869 assembler->Goto(&loop);
3870 assembler->Bind(&loop);
3871 {
3872 // Shared entry points.
3873 Label return_arg(assembler), return_zero(assembler, Label::kDeferred);
3874
3875 // Load the current {arg} value.
3876 Node* arg = var_arg.value();
3877
3878 // Check if {arg} is a Smi.
3879 assembler->GotoIf(assembler->WordIsSmi(arg), &return_arg);
3880
3881 // Check if {arg} is a HeapNumber.
3882 Label if_argisheapnumber(assembler),
3883 if_argisnotheapnumber(assembler, Label::kDeferred);
3884 assembler->Branch(assembler->WordEqual(assembler->LoadMap(arg),
3885 assembler->HeapNumberMapConstant()),
3886 &if_argisheapnumber, &if_argisnotheapnumber);
3887
3888 assembler->Bind(&if_argisheapnumber);
3889 {
3890 // Load the floating-point value of {arg}.
3891 Node* arg_value = assembler->LoadHeapNumberValue(arg);
3892
3893 // Check if {arg} is NaN.
3894 assembler->GotoUnless(assembler->Float64Equal(arg_value, arg_value),
3895 &return_zero);
3896
3897 // Truncate {arg} towards zero.
3898 Node* value = assembler->Float64Trunc(arg_value);
3899 var_arg.Bind(assembler->ChangeFloat64ToTagged(value));
3900 assembler->Goto(&return_arg);
3901 }
3902
3903 assembler->Bind(&if_argisnotheapnumber);
3904 {
3905 // Need to convert {arg} to a Number first.
3906 Callable callable = CodeFactory::NonNumberToNumber(assembler->isolate());
3907 var_arg.Bind(assembler->CallStub(callable, context, arg));
3908 assembler->Goto(&loop);
3909 }
3910
3911 assembler->Bind(&return_arg);
3912 assembler->Return(var_arg.value());
3913
3914 assembler->Bind(&return_zero);
3915 assembler->Return(assembler->SmiConstant(Smi::FromInt(0)));
3916 }
3917}
3918
3919void StoreInterceptorStub::GenerateAssembly(
Ben Murdochc5610432016-08-08 18:44:38 +01003920 CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003921 typedef compiler::Node Node;
3922 Node* receiver = assembler->Parameter(0);
3923 Node* name = assembler->Parameter(1);
3924 Node* value = assembler->Parameter(2);
3925 Node* context = assembler->Parameter(3);
3926 assembler->TailCallRuntime(Runtime::kStorePropertyWithInterceptor, context,
3927 receiver, name, value);
3928}
3929
3930void LoadIndexedInterceptorStub::GenerateAssembly(
Ben Murdochc5610432016-08-08 18:44:38 +01003931 CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003932 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +01003933 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01003934 Node* receiver = assembler->Parameter(0);
3935 Node* key = assembler->Parameter(1);
3936 Node* slot = assembler->Parameter(2);
3937 Node* vector = assembler->Parameter(3);
3938 Node* context = assembler->Parameter(4);
3939
3940 Label if_keyispositivesmi(assembler), if_keyisinvalid(assembler);
3941 assembler->Branch(assembler->WordIsPositiveSmi(key), &if_keyispositivesmi,
3942 &if_keyisinvalid);
3943 assembler->Bind(&if_keyispositivesmi);
3944 assembler->TailCallRuntime(Runtime::kLoadElementWithInterceptor, context,
3945 receiver, key);
3946
3947 assembler->Bind(&if_keyisinvalid);
3948 assembler->TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key,
3949 slot, vector);
3950}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003951
Ben Murdochc5610432016-08-08 18:44:38 +01003952// static
3953bool FastCloneShallowObjectStub::IsSupported(ObjectLiteral* expr) {
3954 // FastCloneShallowObjectStub doesn't copy elements, and object literals don't
3955 // support copy-on-write (COW) elements for now.
3956 // TODO(mvstanton): make object literals support COW elements.
3957 return expr->fast_elements() && expr->has_shallow_properties() &&
3958 expr->properties_count() <= kMaximumClonedProperties;
3959}
3960
3961// static
3962int FastCloneShallowObjectStub::PropertiesCount(int literal_length) {
3963 // This heuristic of setting empty literals to have
3964 // kInitialGlobalObjectUnusedPropertiesCount must remain in-sync with the
3965 // runtime.
3966 // TODO(verwaest): Unify this with the heuristic in the runtime.
3967 return literal_length == 0
3968 ? JSObject::kInitialGlobalObjectUnusedPropertiesCount
3969 : literal_length;
3970}
3971
3972// static
3973compiler::Node* FastCloneShallowObjectStub::GenerateFastPath(
3974 CodeStubAssembler* assembler, compiler::CodeAssembler::Label* call_runtime,
3975 compiler::Node* closure, compiler::Node* literals_index,
3976 compiler::Node* properties_count) {
3977 typedef compiler::Node Node;
3978 typedef compiler::CodeAssembler::Label Label;
3979 typedef compiler::CodeAssembler::Variable Variable;
3980
3981 Node* undefined = assembler->UndefinedConstant();
3982 Node* literals_array =
3983 assembler->LoadObjectField(closure, JSFunction::kLiteralsOffset);
3984 Node* allocation_site = assembler->LoadFixedArrayElement(
3985 literals_array, literals_index,
3986 LiteralsArray::kFirstLiteralIndex * kPointerSize,
3987 CodeStubAssembler::SMI_PARAMETERS);
3988 assembler->GotoIf(assembler->WordEqual(allocation_site, undefined),
3989 call_runtime);
3990
3991 // Calculate the object and allocation size based on the properties count.
3992 Node* object_size = assembler->IntPtrAdd(
3993 assembler->WordShl(properties_count, kPointerSizeLog2),
3994 assembler->IntPtrConstant(JSObject::kHeaderSize));
3995 Node* allocation_size = object_size;
3996 if (FLAG_allocation_site_pretenuring) {
3997 allocation_size = assembler->IntPtrAdd(
3998 object_size, assembler->IntPtrConstant(AllocationMemento::kSize));
3999 }
4000 Node* boilerplate = assembler->LoadObjectField(
4001 allocation_site, AllocationSite::kTransitionInfoOffset);
4002 Node* boilerplate_map = assembler->LoadMap(boilerplate);
4003 Node* instance_size = assembler->LoadMapInstanceSize(boilerplate_map);
4004 Node* size_in_words = assembler->WordShr(object_size, kPointerSizeLog2);
4005 assembler->GotoUnless(assembler->Word32Equal(instance_size, size_in_words),
4006 call_runtime);
4007
4008 Node* copy = assembler->Allocate(allocation_size);
4009
4010 // Copy boilerplate elements.
4011 Variable offset(assembler, MachineType::PointerRepresentation());
4012 offset.Bind(assembler->IntPtrConstant(-kHeapObjectTag));
4013 Node* end_offset = assembler->IntPtrAdd(object_size, offset.value());
4014 Label loop_body(assembler, &offset), loop_check(assembler, &offset);
4015 // We should always have an object size greater than zero.
4016 assembler->Goto(&loop_body);
4017 assembler->Bind(&loop_body);
4018 {
4019 // The Allocate above guarantees that the copy lies in new space. This
4020 // allows us to skip write barriers. This is necessary since we may also be
4021 // copying unboxed doubles.
4022 Node* field =
4023 assembler->Load(MachineType::IntPtr(), boilerplate, offset.value());
4024 assembler->StoreNoWriteBarrier(MachineType::PointerRepresentation(), copy,
4025 offset.value(), field);
4026 assembler->Goto(&loop_check);
4027 }
4028 assembler->Bind(&loop_check);
4029 {
4030 offset.Bind(assembler->IntPtrAdd(offset.value(),
4031 assembler->IntPtrConstant(kPointerSize)));
4032 assembler->GotoUnless(
4033 assembler->IntPtrGreaterThanOrEqual(offset.value(), end_offset),
4034 &loop_body);
4035 }
4036
4037 if (FLAG_allocation_site_pretenuring) {
4038 Node* memento = assembler->InnerAllocate(copy, object_size);
4039 assembler->StoreObjectFieldNoWriteBarrier(
4040 memento, HeapObject::kMapOffset,
4041 assembler->LoadRoot(Heap::kAllocationMementoMapRootIndex));
4042 assembler->StoreObjectFieldNoWriteBarrier(
4043 memento, AllocationMemento::kAllocationSiteOffset, allocation_site);
4044 Node* memento_create_count = assembler->LoadObjectField(
4045 allocation_site, AllocationSite::kPretenureCreateCountOffset);
4046 memento_create_count = assembler->SmiAdd(
4047 memento_create_count, assembler->SmiConstant(Smi::FromInt(1)));
4048 assembler->StoreObjectFieldNoWriteBarrier(
4049 allocation_site, AllocationSite::kPretenureCreateCountOffset,
4050 memento_create_count);
4051 }
4052
4053 // TODO(verwaest): Allocate and fill in double boxes.
4054 return copy;
4055}
4056
4057void FastCloneShallowObjectStub::GenerateAssembly(
4058 CodeStubAssembler* assembler) const {
4059 typedef CodeStubAssembler::Label Label;
4060 typedef compiler::Node Node;
4061 Label call_runtime(assembler);
4062 Node* closure = assembler->Parameter(0);
4063 Node* literals_index = assembler->Parameter(1);
4064
4065 Node* properties_count =
4066 assembler->IntPtrConstant(PropertiesCount(this->length()));
4067 Node* copy = GenerateFastPath(assembler, &call_runtime, closure,
4068 literals_index, properties_count);
4069 assembler->Return(copy);
4070
4071 assembler->Bind(&call_runtime);
4072 Node* constant_properties = assembler->Parameter(2);
4073 Node* flags = assembler->Parameter(3);
4074 Node* context = assembler->Parameter(4);
4075 assembler->TailCallRuntime(Runtime::kCreateObjectLiteral, context, closure,
4076 literals_index, constant_properties, flags);
4077}
4078
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004079template<class StateType>
4080void HydrogenCodeStub::TraceTransition(StateType from, StateType to) {
4081 // Note: Although a no-op transition is semantically OK, it is hinting at a
4082 // bug somewhere in our state transition machinery.
4083 DCHECK(from != to);
4084 if (!FLAG_trace_ic) return;
4085 OFStream os(stdout);
4086 os << "[";
4087 PrintBaseName(os);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004088 os << ": " << from << "=>" << to << "]" << std::endl;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004089}
4090
4091
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004092// TODO(svenpanne) Make this a real infix_ostream_iterator.
4093class SimpleListPrinter {
4094 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004095 explicit SimpleListPrinter(std::ostream& os) : os_(os), first_(true) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004096
4097 void Add(const char* s) {
4098 if (first_) {
4099 first_ = false;
4100 } else {
4101 os_ << ",";
4102 }
4103 os_ << s;
Ben Murdoch086aeea2011-05-13 15:57:08 +01004104 }
4105
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004106 private:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004107 std::ostream& os_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004108 bool first_;
4109};
4110
4111
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004112void CallICStub::PrintState(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004113 os << state();
4114}
4115
4116
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004117void JSEntryStub::FinishCode(Handle<Code> code) {
4118 Handle<FixedArray> handler_table =
4119 code->GetIsolate()->factory()->NewFixedArray(1, TENURED);
4120 handler_table->set(0, Smi::FromInt(handler_offset_));
4121 code->set_handler_table(*handler_table);
4122}
4123
4124
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004125void LoadDictionaryElementStub::InitializeDescriptor(
4126 CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004127 descriptor->Initialize(
4128 FUNCTION_ADDR(Runtime_KeyedLoadIC_MissFromStubFailure));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004129}
4130
4131
4132void KeyedLoadGenericStub::InitializeDescriptor(
4133 CodeStubDescriptor* descriptor) {
4134 descriptor->Initialize(
Ben Murdoch097c5b22016-05-18 11:27:45 +01004135 Runtime::FunctionForId(Runtime::kKeyedGetProperty)->entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004136}
4137
4138
4139void HandlerStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
4140 if (kind() == Code::STORE_IC) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004141 descriptor->Initialize(FUNCTION_ADDR(Runtime_StoreIC_MissFromStubFailure));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004142 } else if (kind() == Code::KEYED_LOAD_IC) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004143 descriptor->Initialize(
4144 FUNCTION_ADDR(Runtime_KeyedLoadIC_MissFromStubFailure));
4145 } else if (kind() == Code::KEYED_STORE_IC) {
4146 descriptor->Initialize(
4147 FUNCTION_ADDR(Runtime_KeyedStoreIC_MissFromStubFailure));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004148 }
4149}
4150
4151
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004152CallInterfaceDescriptor HandlerStub::GetCallInterfaceDescriptor() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004153 if (kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004154 return LoadWithVectorDescriptor(isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004155 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004156 DCHECK(kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC);
4157 return VectorStoreICDescriptor(isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004158 }
4159}
4160
4161
4162void StoreFastElementStub::InitializeDescriptor(
4163 CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004164 descriptor->Initialize(
4165 FUNCTION_ADDR(Runtime_KeyedStoreIC_MissFromStubFailure));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004166}
4167
4168
4169void ElementsTransitionAndStoreStub::InitializeDescriptor(
4170 CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004171 descriptor->Initialize(
4172 FUNCTION_ADDR(Runtime_ElementsTransitionAndStoreIC_Miss));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004173}
4174
4175
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004176void ToObjectStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
4177 descriptor->Initialize(Runtime::FunctionForId(Runtime::kToObject)->entry);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004178}
4179
4180
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004181CallInterfaceDescriptor StoreTransitionStub::GetCallInterfaceDescriptor()
4182 const {
4183 return VectorStoreTransitionDescriptor(isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004184}
4185
4186
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004187CallInterfaceDescriptor
4188ElementsTransitionAndStoreStub::GetCallInterfaceDescriptor() const {
4189 return VectorStoreTransitionDescriptor(isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004190}
4191
Ben Murdochc5610432016-08-08 18:44:38 +01004192void FastNewClosureStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004193
4194void FastNewContextStub::InitializeDescriptor(CodeStubDescriptor* d) {}
4195
4196
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004197void TypeofStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {}
4198
4199
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004200void NumberToStringStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004201 descriptor->Initialize(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004202 Runtime::FunctionForId(Runtime::kNumberToString)->entry);
4203}
4204
4205
4206void FastCloneRegExpStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
4207 FastCloneRegExpDescriptor call_descriptor(isolate());
4208 descriptor->Initialize(
4209 Runtime::FunctionForId(Runtime::kCreateRegExpLiteral)->entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004210}
4211
4212
4213void FastCloneShallowArrayStub::InitializeDescriptor(
4214 CodeStubDescriptor* descriptor) {
4215 FastCloneShallowArrayDescriptor call_descriptor(isolate());
4216 descriptor->Initialize(
4217 Runtime::FunctionForId(Runtime::kCreateArrayLiteralStubBailout)->entry);
4218}
4219
4220
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004221void CreateAllocationSiteStub::InitializeDescriptor(CodeStubDescriptor* d) {}
4222
4223
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004224void CreateWeakCellStub::InitializeDescriptor(CodeStubDescriptor* d) {}
4225
4226
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004227void RegExpConstructResultStub::InitializeDescriptor(
4228 CodeStubDescriptor* descriptor) {
4229 descriptor->Initialize(
4230 Runtime::FunctionForId(Runtime::kRegExpConstructResult)->entry);
4231}
4232
4233
4234void TransitionElementsKindStub::InitializeDescriptor(
4235 CodeStubDescriptor* descriptor) {
4236 descriptor->Initialize(
4237 Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry);
4238}
4239
4240
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004241void AllocateHeapNumberStub::InitializeDescriptor(
4242 CodeStubDescriptor* descriptor) {
4243 descriptor->Initialize(
4244 Runtime::FunctionForId(Runtime::kAllocateHeapNumber)->entry);
4245}
4246
4247
Ben Murdochda12d292016-06-02 14:46:10 +01004248#define SIMD128_INIT_DESC(TYPE, Type, type, lane_count, lane_type) \
4249 void Allocate##Type##Stub::InitializeDescriptor( \
4250 CodeStubDescriptor* descriptor) { \
4251 descriptor->Initialize( \
4252 Runtime::FunctionForId(Runtime::kCreate##Type)->entry); \
4253 }
4254SIMD128_TYPES(SIMD128_INIT_DESC)
4255#undef SIMD128_INIT_DESC
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004256
Ben Murdochda12d292016-06-02 14:46:10 +01004257void ToBooleanICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004258 descriptor->Initialize(FUNCTION_ADDR(Runtime_ToBooleanIC_Miss));
4259 descriptor->SetMissHandler(ExternalReference(
4260 Runtime::FunctionForId(Runtime::kToBooleanIC_Miss), isolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004261}
4262
4263
4264void BinaryOpICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004265 descriptor->Initialize(FUNCTION_ADDR(Runtime_BinaryOpIC_Miss));
4266 descriptor->SetMissHandler(ExternalReference(
4267 Runtime::FunctionForId(Runtime::kBinaryOpIC_Miss), isolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004268}
4269
4270
4271void BinaryOpWithAllocationSiteStub::InitializeDescriptor(
4272 CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004273 descriptor->Initialize(
4274 FUNCTION_ADDR(Runtime_BinaryOpIC_MissWithAllocationSite));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004275}
4276
4277
4278void StringAddStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
4279 descriptor->Initialize(Runtime::FunctionForId(Runtime::kStringAdd)->entry);
4280}
4281
4282
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004283void GrowArrayElementsStub::InitializeDescriptor(
4284 CodeStubDescriptor* descriptor) {
4285 descriptor->Initialize(
4286 Runtime::FunctionForId(Runtime::kGrowArrayElements)->entry);
4287}
4288
4289
4290void TypeofStub::GenerateAheadOfTime(Isolate* isolate) {
4291 TypeofStub stub(isolate);
4292 stub.GetCode();
4293}
4294
Ben Murdoch61f157c2016-09-16 13:49:30 +01004295// static
4296compiler::Node* HasPropertyStub::Generate(CodeStubAssembler* assembler,
4297 compiler::Node* key,
4298 compiler::Node* object,
4299 compiler::Node* context) {
Ben Murdochc5610432016-08-08 18:44:38 +01004300 typedef compiler::Node Node;
4301 typedef CodeStubAssembler::Label Label;
4302 typedef CodeStubAssembler::Variable Variable;
4303
Ben Murdoch61f157c2016-09-16 13:49:30 +01004304 Label call_runtime(assembler, Label::kDeferred), return_true(assembler),
4305 return_false(assembler), end(assembler);
Ben Murdochc5610432016-08-08 18:44:38 +01004306
4307 // Ensure object is JSReceiver, otherwise call runtime to throw error.
4308 Label if_objectisnotsmi(assembler);
4309 assembler->Branch(assembler->WordIsSmi(object), &call_runtime,
4310 &if_objectisnotsmi);
4311 assembler->Bind(&if_objectisnotsmi);
4312
4313 Node* map = assembler->LoadMap(object);
4314 Node* instance_type = assembler->LoadMapInstanceType(map);
4315 {
4316 Label if_objectisreceiver(assembler);
4317 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
4318 assembler->Branch(
4319 assembler->Int32GreaterThanOrEqual(
4320 instance_type, assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE)),
4321 &if_objectisreceiver, &call_runtime);
4322 assembler->Bind(&if_objectisreceiver);
4323 }
4324
4325 Variable var_index(assembler, MachineRepresentation::kWord32);
4326
4327 Label keyisindex(assembler), if_iskeyunique(assembler);
4328 assembler->TryToName(key, &keyisindex, &var_index, &if_iskeyunique,
4329 &call_runtime);
4330
4331 assembler->Bind(&if_iskeyunique);
4332 {
4333 Variable var_object(assembler, MachineRepresentation::kTagged);
4334 Variable var_map(assembler, MachineRepresentation::kTagged);
4335 Variable var_instance_type(assembler, MachineRepresentation::kWord8);
4336
4337 Variable* merged_variables[] = {&var_object, &var_map, &var_instance_type};
4338 Label loop(assembler, arraysize(merged_variables), merged_variables);
4339 var_object.Bind(object);
4340 var_map.Bind(map);
4341 var_instance_type.Bind(instance_type);
4342 assembler->Goto(&loop);
4343 assembler->Bind(&loop);
4344 {
4345 Label next_proto(assembler);
Ben Murdoch61f157c2016-09-16 13:49:30 +01004346 assembler->TryHasOwnProperty(var_object.value(), var_map.value(),
Ben Murdochc5610432016-08-08 18:44:38 +01004347 var_instance_type.value(), key, &return_true,
4348 &next_proto, &call_runtime);
4349 assembler->Bind(&next_proto);
4350
4351 Node* proto = assembler->LoadMapPrototype(var_map.value());
4352
4353 Label if_not_null(assembler);
4354 assembler->Branch(assembler->WordEqual(proto, assembler->NullConstant()),
4355 &return_false, &if_not_null);
4356 assembler->Bind(&if_not_null);
4357
4358 Node* map = assembler->LoadMap(proto);
4359 Node* instance_type = assembler->LoadMapInstanceType(map);
4360
4361 var_object.Bind(proto);
4362 var_map.Bind(map);
4363 var_instance_type.Bind(instance_type);
4364 assembler->Goto(&loop);
4365 }
4366 }
4367 assembler->Bind(&keyisindex);
4368 {
4369 Variable var_object(assembler, MachineRepresentation::kTagged);
4370 Variable var_map(assembler, MachineRepresentation::kTagged);
4371 Variable var_instance_type(assembler, MachineRepresentation::kWord8);
4372
4373 Variable* merged_variables[] = {&var_object, &var_map, &var_instance_type};
4374 Label loop(assembler, arraysize(merged_variables), merged_variables);
4375 var_object.Bind(object);
4376 var_map.Bind(map);
4377 var_instance_type.Bind(instance_type);
4378 assembler->Goto(&loop);
4379 assembler->Bind(&loop);
4380 {
4381 Label next_proto(assembler);
4382 assembler->TryLookupElement(var_object.value(), var_map.value(),
4383 var_instance_type.value(), var_index.value(),
4384 &return_true, &next_proto, &call_runtime);
4385 assembler->Bind(&next_proto);
4386
4387 Node* proto = assembler->LoadMapPrototype(var_map.value());
4388
4389 Label if_not_null(assembler);
4390 assembler->Branch(assembler->WordEqual(proto, assembler->NullConstant()),
4391 &return_false, &if_not_null);
4392 assembler->Bind(&if_not_null);
4393
4394 Node* map = assembler->LoadMap(proto);
4395 Node* instance_type = assembler->LoadMapInstanceType(map);
4396
4397 var_object.Bind(proto);
4398 var_map.Bind(map);
4399 var_instance_type.Bind(instance_type);
4400 assembler->Goto(&loop);
4401 }
4402 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01004403
4404 Variable result(assembler, MachineRepresentation::kTagged);
Ben Murdochc5610432016-08-08 18:44:38 +01004405 assembler->Bind(&return_true);
Ben Murdoch61f157c2016-09-16 13:49:30 +01004406 {
4407 result.Bind(assembler->BooleanConstant(true));
4408 assembler->Goto(&end);
4409 }
Ben Murdochc5610432016-08-08 18:44:38 +01004410
4411 assembler->Bind(&return_false);
Ben Murdoch61f157c2016-09-16 13:49:30 +01004412 {
4413 result.Bind(assembler->BooleanConstant(false));
4414 assembler->Goto(&end);
4415 }
Ben Murdochc5610432016-08-08 18:44:38 +01004416
4417 assembler->Bind(&call_runtime);
Ben Murdoch61f157c2016-09-16 13:49:30 +01004418 {
4419 result.Bind(
4420 assembler->CallRuntime(Runtime::kHasProperty, context, key, object));
4421 assembler->Goto(&end);
4422 }
4423
4424 assembler->Bind(&end);
4425 return result.value();
Ben Murdochc5610432016-08-08 18:44:38 +01004426}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004427
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004428void CreateAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
4429 CreateAllocationSiteStub stub(isolate);
4430 stub.GetCode();
4431}
4432
4433
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004434void CreateWeakCellStub::GenerateAheadOfTime(Isolate* isolate) {
4435 CreateWeakCellStub stub(isolate);
4436 stub.GetCode();
4437}
4438
4439
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004440void StoreElementStub::Generate(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004441 DCHECK_EQ(DICTIONARY_ELEMENTS, elements_kind());
4442 ElementHandlerCompiler::GenerateStoreSlow(masm);
Ben Murdoch257744e2011-11-30 15:57:28 +00004443}
4444
4445
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004446// static
4447void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) {
4448 StoreFastElementStub(isolate, false, FAST_HOLEY_ELEMENTS, STANDARD_STORE)
4449 .GetCode();
4450 StoreFastElementStub(isolate, false, FAST_HOLEY_ELEMENTS,
4451 STORE_AND_GROW_NO_TRANSITION).GetCode();
4452 for (int i = FIRST_FAST_ELEMENTS_KIND; i <= LAST_FAST_ELEMENTS_KIND; i++) {
4453 ElementsKind kind = static_cast<ElementsKind>(i);
4454 StoreFastElementStub(isolate, true, kind, STANDARD_STORE).GetCode();
4455 StoreFastElementStub(isolate, true, kind, STORE_AND_GROW_NO_TRANSITION)
4456 .GetCode();
4457 }
4458}
4459
4460
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004461void ArrayConstructorStub::PrintName(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004462 os << "ArrayConstructorStub";
4463 switch (argument_count()) {
4464 case ANY:
4465 os << "_Any";
4466 break;
4467 case NONE:
4468 os << "_None";
4469 break;
4470 case ONE:
4471 os << "_One";
4472 break;
4473 case MORE_THAN_ONE:
4474 os << "_More_Than_One";
4475 break;
4476 }
4477 return;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004478}
4479
4480
Ben Murdochda12d292016-06-02 14:46:10 +01004481bool ToBooleanICStub::UpdateStatus(Handle<Object> object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004482 Types new_types = types();
4483 Types old_types = new_types;
Ben Murdoch61f157c2016-09-16 13:49:30 +01004484 bool to_boolean_value = new_types.UpdateStatus(isolate(), object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004485 TraceTransition(old_types, new_types);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004486 set_sub_minor_key(TypesBits::update(sub_minor_key(), new_types.ToIntegral()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004487 return to_boolean_value;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004488}
4489
Ben Murdochda12d292016-06-02 14:46:10 +01004490void ToBooleanICStub::PrintState(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004491 os << types();
4492}
4493
Ben Murdochda12d292016-06-02 14:46:10 +01004494std::ostream& operator<<(std::ostream& os, const ToBooleanICStub::Types& s) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004495 os << "(";
4496 SimpleListPrinter p(os);
4497 if (s.IsEmpty()) p.Add("None");
Ben Murdochda12d292016-06-02 14:46:10 +01004498 if (s.Contains(ToBooleanICStub::UNDEFINED)) p.Add("Undefined");
4499 if (s.Contains(ToBooleanICStub::BOOLEAN)) p.Add("Bool");
4500 if (s.Contains(ToBooleanICStub::NULL_TYPE)) p.Add("Null");
4501 if (s.Contains(ToBooleanICStub::SMI)) p.Add("Smi");
4502 if (s.Contains(ToBooleanICStub::SPEC_OBJECT)) p.Add("SpecObject");
4503 if (s.Contains(ToBooleanICStub::STRING)) p.Add("String");
4504 if (s.Contains(ToBooleanICStub::SYMBOL)) p.Add("Symbol");
4505 if (s.Contains(ToBooleanICStub::HEAP_NUMBER)) p.Add("HeapNumber");
4506 if (s.Contains(ToBooleanICStub::SIMD_VALUE)) p.Add("SimdValue");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004507 return os << ")";
4508}
4509
Ben Murdoch61f157c2016-09-16 13:49:30 +01004510bool ToBooleanICStub::Types::UpdateStatus(Isolate* isolate,
4511 Handle<Object> object) {
4512 if (object->IsUndefined(isolate)) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004513 Add(UNDEFINED);
4514 return false;
4515 } else if (object->IsBoolean()) {
4516 Add(BOOLEAN);
Ben Murdoch61f157c2016-09-16 13:49:30 +01004517 return object->IsTrue(isolate);
4518 } else if (object->IsNull(isolate)) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004519 Add(NULL_TYPE);
4520 return false;
4521 } else if (object->IsSmi()) {
4522 Add(SMI);
4523 return Smi::cast(*object)->value() != 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004524 } else if (object->IsJSReceiver()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004525 Add(SPEC_OBJECT);
Ben Murdochda12d292016-06-02 14:46:10 +01004526 return !object->IsUndetectable();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004527 } else if (object->IsString()) {
Ben Murdochda12d292016-06-02 14:46:10 +01004528 DCHECK(!object->IsUndetectable());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004529 Add(STRING);
Ben Murdoch097c5b22016-05-18 11:27:45 +01004530 return String::cast(*object)->length() != 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004531 } else if (object->IsSymbol()) {
4532 Add(SYMBOL);
4533 return true;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004534 } else if (object->IsHeapNumber()) {
Ben Murdochda12d292016-06-02 14:46:10 +01004535 DCHECK(!object->IsUndetectable());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004536 Add(HEAP_NUMBER);
4537 double value = HeapNumber::cast(*object)->value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004538 return value != 0 && !std::isnan(value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004539 } else if (object->IsSimd128Value()) {
4540 Add(SIMD_VALUE);
4541 return true;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004542 } else {
4543 // We should never see an internal object at runtime here!
4544 UNREACHABLE();
4545 return true;
4546 }
4547}
4548
Ben Murdochda12d292016-06-02 14:46:10 +01004549bool ToBooleanICStub::Types::NeedsMap() const {
4550 return Contains(ToBooleanICStub::SPEC_OBJECT) ||
4551 Contains(ToBooleanICStub::STRING) ||
4552 Contains(ToBooleanICStub::SYMBOL) ||
4553 Contains(ToBooleanICStub::HEAP_NUMBER) ||
4554 Contains(ToBooleanICStub::SIMD_VALUE);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004555}
4556
4557
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004558void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) {
4559 StubFailureTrampolineStub stub1(isolate, NOT_JS_FUNCTION_STUB_MODE);
4560 StubFailureTrampolineStub stub2(isolate, JS_FUNCTION_STUB_MODE);
4561 stub1.GetCode();
4562 stub2.GetCode();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004563}
4564
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004565
4566void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function,
4567 intptr_t stack_pointer,
4568 Isolate* isolate) {
4569 FunctionEntryHook entry_hook = isolate->function_entry_hook();
4570 DCHECK(entry_hook != NULL);
4571 entry_hook(function, stack_pointer);
4572}
4573
Ben Murdochc5610432016-08-08 18:44:38 +01004574void ArrayNoArgumentConstructorStub::GenerateAssembly(
4575 CodeStubAssembler* assembler) const {
4576 typedef compiler::Node Node;
4577 Node* native_context = assembler->LoadObjectField(
4578 assembler->Parameter(
4579 ArrayNoArgumentConstructorDescriptor::kFunctionIndex),
4580 JSFunction::kContextOffset);
4581 bool track_allocation_site =
4582 AllocationSite::GetMode(elements_kind()) == TRACK_ALLOCATION_SITE &&
4583 override_mode() != DISABLE_ALLOCATION_SITES;
4584 Node* allocation_site =
4585 track_allocation_site
4586 ? assembler->Parameter(
4587 ArrayNoArgumentConstructorDescriptor::kAllocationSiteIndex)
4588 : nullptr;
4589 Node* array_map =
4590 assembler->LoadJSArrayElementsMap(elements_kind(), native_context);
4591 Node* array = assembler->AllocateJSArray(
4592 elements_kind(), array_map,
4593 assembler->IntPtrConstant(JSArray::kPreallocatedArrayElements),
4594 assembler->IntPtrConstant(0), allocation_site);
4595 assembler->Return(array);
4596}
4597
4598void InternalArrayNoArgumentConstructorStub::GenerateAssembly(
4599 CodeStubAssembler* assembler) const {
4600 typedef compiler::Node Node;
4601 Node* array_map = assembler->LoadObjectField(
4602 assembler->Parameter(
4603 ArrayNoArgumentConstructorDescriptor::kFunctionIndex),
4604 JSFunction::kPrototypeOrInitialMapOffset);
4605 Node* array = assembler->AllocateJSArray(
4606 elements_kind(), array_map,
4607 assembler->IntPtrConstant(JSArray::kPreallocatedArrayElements),
4608 assembler->IntPtrConstant(0), nullptr);
4609 assembler->Return(array);
4610}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004611
Ben Murdoch61f157c2016-09-16 13:49:30 +01004612namespace {
4613
4614void SingleArgumentConstructorCommon(CodeStubAssembler* assembler,
4615 ElementsKind elements_kind,
4616 compiler::Node* array_map,
4617 compiler::Node* allocation_site,
4618 AllocationSiteMode mode) {
4619 typedef compiler::Node Node;
4620 typedef CodeStubAssembler::Label Label;
4621
4622 Label ok(assembler);
4623 Label smi_size(assembler);
4624 Label small_smi_size(assembler);
4625 Label call_runtime(assembler, Label::kDeferred);
4626
4627 Node* size = assembler->Parameter(
4628 ArraySingleArgumentConstructorDescriptor::kArraySizeSmiParameterIndex);
4629 assembler->Branch(assembler->WordIsSmi(size), &smi_size, &call_runtime);
4630
4631 assembler->Bind(&smi_size);
4632 int element_size =
4633 IsFastDoubleElementsKind(elements_kind) ? kDoubleSize : kPointerSize;
4634 int max_fast_elements =
4635 (Page::kMaxRegularHeapObjectSize - FixedArray::kHeaderSize -
4636 JSArray::kSize - AllocationMemento::kSize) /
4637 element_size;
4638 assembler->Branch(
4639 assembler->SmiAboveOrEqual(
4640 size, assembler->SmiConstant(Smi::FromInt(max_fast_elements))),
4641 &call_runtime, &small_smi_size);
4642
4643 assembler->Bind(&small_smi_size);
4644 {
4645 Node* array = assembler->AllocateJSArray(
4646 elements_kind, array_map, size, size,
4647 mode == DONT_TRACK_ALLOCATION_SITE ? nullptr : allocation_site,
4648 CodeStubAssembler::SMI_PARAMETERS);
4649 assembler->Return(array);
4650 }
4651
4652 assembler->Bind(&call_runtime);
4653 {
4654 Node* context = assembler->Parameter(
4655 ArraySingleArgumentConstructorDescriptor::kContextIndex);
4656 Node* function = assembler->Parameter(
4657 ArraySingleArgumentConstructorDescriptor::kFunctionIndex);
4658 Node* array_size = assembler->Parameter(
4659 ArraySingleArgumentConstructorDescriptor::kArraySizeSmiParameterIndex);
4660 Node* allocation_site = assembler->Parameter(
4661 ArraySingleArgumentConstructorDescriptor::kAllocationSiteIndex);
4662 assembler->TailCallRuntime(Runtime::kNewArray, context, function,
4663 array_size, function, allocation_site);
4664 }
4665}
4666} // namespace
4667
4668void ArraySingleArgumentConstructorStub::GenerateAssembly(
4669 CodeStubAssembler* assembler) const {
4670 typedef compiler::Node Node;
4671 Node* function = assembler->Parameter(
4672 ArraySingleArgumentConstructorDescriptor::kFunctionIndex);
4673 Node* native_context =
4674 assembler->LoadObjectField(function, JSFunction::kContextOffset);
4675 Node* array_map =
4676 assembler->LoadJSArrayElementsMap(elements_kind(), native_context);
4677 AllocationSiteMode mode = override_mode() == DISABLE_ALLOCATION_SITES
4678 ? DONT_TRACK_ALLOCATION_SITE
4679 : AllocationSite::GetMode(elements_kind());
4680 Node* allocation_site = assembler->Parameter(
4681 ArrayNoArgumentConstructorDescriptor::kAllocationSiteIndex);
4682 SingleArgumentConstructorCommon(assembler, elements_kind(), array_map,
4683 allocation_site, mode);
4684}
4685
4686void InternalArraySingleArgumentConstructorStub::GenerateAssembly(
4687 CodeStubAssembler* assembler) const {
4688 typedef compiler::Node Node;
4689 Node* function = assembler->Parameter(
4690 ArraySingleArgumentConstructorDescriptor::kFunctionIndex);
4691 Node* array_map = assembler->LoadObjectField(
4692 function, JSFunction::kPrototypeOrInitialMapOffset);
4693 SingleArgumentConstructorCommon(assembler, elements_kind(), array_map,
4694 assembler->UndefinedConstant(),
4695 DONT_TRACK_ALLOCATION_SITE);
4696}
4697
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004698ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate)
4699 : PlatformCodeStub(isolate) {
4700 minor_key_ = ArgumentCountBits::encode(ANY);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004701}
4702
4703
4704ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate,
4705 int argument_count)
4706 : PlatformCodeStub(isolate) {
4707 if (argument_count == 0) {
4708 minor_key_ = ArgumentCountBits::encode(NONE);
4709 } else if (argument_count == 1) {
4710 minor_key_ = ArgumentCountBits::encode(ONE);
4711 } else if (argument_count >= 2) {
4712 minor_key_ = ArgumentCountBits::encode(MORE_THAN_ONE);
4713 } else {
4714 UNREACHABLE();
4715 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004716}
4717
Ben Murdoch61f157c2016-09-16 13:49:30 +01004718InternalArrayConstructorStub::InternalArrayConstructorStub(Isolate* isolate)
4719 : PlatformCodeStub(isolate) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004720
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004721Representation RepresentationFromType(Type* type) {
4722 if (type->Is(Type::UntaggedIntegral())) {
4723 return Representation::Integer32();
4724 }
4725
4726 if (type->Is(Type::TaggedSigned())) {
4727 return Representation::Smi();
4728 }
4729
4730 if (type->Is(Type::UntaggedPointer())) {
4731 return Representation::External();
4732 }
4733
4734 DCHECK(!type->Is(Type::Untagged()));
4735 return Representation::Tagged();
4736}
4737
4738} // namespace internal
4739} // namespace v8