blob: 60b350cd93b22c702053057d0cbfb0bdf572e844 [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 Murdoch4a90d5f2016-03-22 12:00:34 +000011#include "src/compiler/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"
18#include "src/profiler/cpu-profiler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000019
20namespace v8 {
21namespace internal {
22
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000024RUNTIME_FUNCTION(UnexpectedStubMiss) {
25 FATAL("Unexpected deopt of a stub");
26 return Smi::FromInt(0);
27}
28
29
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030CodeStubDescriptor::CodeStubDescriptor(CodeStub* stub)
31 : call_descriptor_(stub->GetCallInterfaceDescriptor()),
32 stack_parameter_count_(no_reg),
33 hint_stack_parameter_count_(-1),
34 function_mode_(NOT_JS_FUNCTION_STUB_MODE),
35 deoptimization_handler_(NULL),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000036 miss_handler_(),
37 has_miss_handler_(false) {
38 stub->InitializeDescriptor(this);
39}
40
41
42CodeStubDescriptor::CodeStubDescriptor(Isolate* isolate, uint32_t stub_key)
43 : stack_parameter_count_(no_reg),
44 hint_stack_parameter_count_(-1),
45 function_mode_(NOT_JS_FUNCTION_STUB_MODE),
46 deoptimization_handler_(NULL),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000047 miss_handler_(),
48 has_miss_handler_(false) {
49 CodeStub::InitializeDescriptor(isolate, stub_key, this);
50}
51
52
53void CodeStubDescriptor::Initialize(Address deoptimization_handler,
54 int hint_stack_parameter_count,
55 StubFunctionMode function_mode) {
56 deoptimization_handler_ = deoptimization_handler;
57 hint_stack_parameter_count_ = hint_stack_parameter_count;
58 function_mode_ = function_mode;
59}
60
61
62void CodeStubDescriptor::Initialize(Register stack_parameter_count,
63 Address deoptimization_handler,
64 int hint_stack_parameter_count,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065 StubFunctionMode function_mode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000066 Initialize(deoptimization_handler, hint_stack_parameter_count, function_mode);
67 stack_parameter_count_ = stack_parameter_count;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000068}
69
70
Leon Clarkee46be812010-01-19 14:06:41 +000071bool CodeStub::FindCodeInCache(Code** code_out) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000072 UnseededNumberDictionary* stubs = isolate()->heap()->code_stubs();
73 int index = stubs->FindEntry(GetKey());
Ben Murdochc7cc0282012-03-05 14:35:55 +000074 if (index != UnseededNumberDictionary::kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000075 *code_out = Code::cast(stubs->ValueAt(index));
Leon Clarkee46be812010-01-19 14:06:41 +000076 return true;
Steve Blockd0582a62009-12-15 09:54:21 +000077 }
Leon Clarkee46be812010-01-19 14:06:41 +000078 return false;
79}
Steve Blockd0582a62009-12-15 09:54:21 +000080
Leon Clarkee46be812010-01-19 14:06:41 +000081
Ben Murdochb8a8cc12014-11-26 15:28:44 +000082void CodeStub::RecordCodeGeneration(Handle<Code> code) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040083 std::ostringstream os;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000084 os << *this;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040085 PROFILE(isolate(),
Ben Murdochda12d292016-06-02 14:46:10 +010086 CodeCreateEvent(Logger::STUB_TAG, AbstractCode::cast(*code),
87 os.str().c_str()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000088 Counters* counters = isolate()->counters();
Steve Block44f0eee2011-05-26 01:26:41 +010089 counters->total_stubs_code_size()->Increment(code->instruction_size());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000090#ifdef DEBUG
91 code->VerifyEmbeddedObjects();
92#endif
Leon Clarkee46be812010-01-19 14:06:41 +000093}
94
95
Ben Murdochb8a8cc12014-11-26 15:28:44 +000096Code::Kind CodeStub::GetCodeKind() const {
Steve Block6ded16b2010-05-10 14:33:55 +010097 return Code::STUB;
98}
99
100
Ben Murdoch097c5b22016-05-18 11:27:45 +0100101Code::Flags CodeStub::GetCodeFlags() const {
102 return Code::ComputeFlags(GetCodeKind(), GetICState(), GetExtraICState(),
103 GetStubType());
104}
105
106
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000107Handle<Code> CodeStub::GetCodeCopy(const Code::FindAndReplacePattern& pattern) {
108 Handle<Code> ic = GetCode();
109 ic = isolate()->factory()->CopyCode(ic);
110 ic->FindAndReplace(pattern);
111 RecordCodeGeneration(ic);
112 return ic;
113}
114
115
116Handle<Code> PlatformCodeStub::GenerateCode() {
117 Factory* factory = isolate()->factory();
118
119 // Generate the new code.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000120 MacroAssembler masm(isolate(), NULL, 256, CodeObjectRequired::kYes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000121
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000122 {
123 // Update the static counter each time a new code stub is generated.
124 isolate()->counters()->code_stubs()->Increment();
125
126 // Generate the code for the stub.
127 masm.set_generating_stub(true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400128 // TODO(yangguo): remove this once we can serialize IC stubs.
129 masm.enable_serializer();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000130 NoCurrentFrameScope scope(&masm);
131 Generate(&masm);
132 }
133
134 // Create the code object.
135 CodeDesc desc;
136 masm.GetCode(&desc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000137 // Copy the generated code into a heap object.
138 Code::Flags flags = Code::ComputeFlags(
139 GetCodeKind(),
140 GetICState(),
141 GetExtraICState(),
142 GetStubType());
143 Handle<Code> new_object = factory->NewCode(
144 desc, flags, masm.CodeObject(), NeedsImmovableCode());
145 return new_object;
146}
147
148
Leon Clarkee46be812010-01-19 14:06:41 +0000149Handle<Code> CodeStub::GetCode() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000150 Heap* heap = isolate()->heap();
Leon Clarkee46be812010-01-19 14:06:41 +0000151 Code* code;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000152 if (UseSpecialCache() ? FindCodeInSpecialCache(&code)
153 : FindCodeInCache(&code)) {
154 DCHECK(GetCodeKind() == code->kind());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100155 return Handle<Code>(code);
156 }
157
158 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000159 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000160
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161 Handle<Code> new_object = GenerateCode();
162 new_object->set_stub_key(GetKey());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100163 FinishCode(new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000164 RecordCodeGeneration(new_object);
165
166#ifdef ENABLE_DISASSEMBLER
167 if (FLAG_print_code_stubs) {
168 CodeTracer::Scope trace_scope(isolate()->GetCodeTracer());
169 OFStream os(trace_scope.file());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400170 std::ostringstream name;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000171 name << *this;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400172 new_object->Disassemble(name.str().c_str(), os);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000173 os << "\n";
174 }
175#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000176
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100177 if (UseSpecialCache()) {
178 AddToSpecialCache(new_object);
179 } else {
180 // Update the dictionary and the root in Heap.
181 Handle<UnseededNumberDictionary> dict =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000182 UnseededNumberDictionary::AtNumberPut(
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100183 Handle<UnseededNumberDictionary>(heap->code_stubs()),
184 GetKey(),
185 new_object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000186 heap->SetRootCodeStubs(*dict);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100187 }
Leon Clarkee46be812010-01-19 14:06:41 +0000188 code = *new_object;
Steve Blocka7e24c12009-10-30 11:49:00 +0000189 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000190
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100191 Activate(code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000192 DCHECK(!NeedsImmovableCode() ||
193 heap->lo_space()->Contains(code) ||
194 heap->code_space()->FirstPage()->Contains(code->address()));
195 return Handle<Code>(code, isolate());
Leon Clarkee46be812010-01-19 14:06:41 +0000196}
197
198
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000199const char* CodeStub::MajorName(CodeStub::Major major_key) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000200 switch (major_key) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000201#define DEF_CASE(name) case name: return #name "Stub";
Steve Blockd0582a62009-12-15 09:54:21 +0000202 CODE_STUB_LIST(DEF_CASE)
203#undef DEF_CASE
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000204 case NoCache:
205 return "<NoCache>Stub";
206 case NUMBER_OF_IDS:
207 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +0000208 return NULL;
209 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000210 return NULL;
211}
212
213
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400214void CodeStub::PrintBaseName(std::ostream& os) const { // NOLINT
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000215 os << MajorName(MajorKey());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000216}
217
218
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400219void CodeStub::PrintName(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000220 PrintBaseName(os);
221 PrintState(os);
222}
223
224
225void CodeStub::Dispatch(Isolate* isolate, uint32_t key, void** value_out,
226 DispatchedCall call) {
227 switch (MajorKeyFromKey(key)) {
228#define DEF_CASE(NAME) \
229 case NAME: { \
230 NAME##Stub stub(key, isolate); \
231 CodeStub* pstub = &stub; \
232 call(pstub, value_out); \
233 break; \
234 }
235 CODE_STUB_LIST(DEF_CASE)
236#undef DEF_CASE
237 case NUMBER_OF_IDS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000238 case NoCache:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400239 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000240 break;
241 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000242}
243
244
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000245static void InitializeDescriptorDispatchedCall(CodeStub* stub,
246 void** value_out) {
247 CodeStubDescriptor* descriptor_out =
248 reinterpret_cast<CodeStubDescriptor*>(value_out);
249 stub->InitializeDescriptor(descriptor_out);
250 descriptor_out->set_call_descriptor(stub->GetCallInterfaceDescriptor());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100251}
252
253
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000254void CodeStub::InitializeDescriptor(Isolate* isolate, uint32_t key,
255 CodeStubDescriptor* desc) {
256 void** value_out = reinterpret_cast<void**>(desc);
257 Dispatch(isolate, key, value_out, &InitializeDescriptorDispatchedCall);
258}
259
260
261void CodeStub::GetCodeDispatchCall(CodeStub* stub, void** value_out) {
262 Handle<Code>* code_out = reinterpret_cast<Handle<Code>*>(value_out);
263 // Code stubs with special cache cannot be recreated from stub key.
264 *code_out = stub->UseSpecialCache() ? Handle<Code>() : stub->GetCode();
265}
266
267
268MaybeHandle<Code> CodeStub::GetCode(Isolate* isolate, uint32_t key) {
269 HandleScope scope(isolate);
270 Handle<Code> code;
271 void** value_out = reinterpret_cast<void**>(&code);
272 Dispatch(isolate, key, value_out, &GetCodeDispatchCall);
273 return scope.CloseAndEscape(code);
274}
275
276
277// static
278void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate) {
279 // Generate the uninitialized versions of the stub.
280 for (int op = Token::BIT_OR; op <= Token::MOD; ++op) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100281 BinaryOpICStub stub(isolate, static_cast<Token::Value>(op));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000282 stub.GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000283 }
284
285 // Generate special versions of the stub.
286 BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
287}
288
289
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400290void BinaryOpICStub::PrintState(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000291 os << state();
292}
293
294
295// static
296void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate,
297 const BinaryOpICState& state) {
298 BinaryOpICStub stub(isolate, state);
299 stub.GetCode();
300}
301
302
303// static
304void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
305 // Generate special versions of the stub.
306 BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
307}
308
309
310void BinaryOpICWithAllocationSiteStub::PrintState(
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400311 std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000312 os << state();
313}
314
315
316// static
317void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(
318 Isolate* isolate, const BinaryOpICState& state) {
319 if (state.CouldCreateAllocationMementos()) {
320 BinaryOpICWithAllocationSiteStub stub(isolate, state);
321 stub.GetCode();
322 }
323}
324
325
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000326std::ostream& operator<<(std::ostream& os, const StringAddFlags& flags) {
327 switch (flags) {
328 case STRING_ADD_CHECK_NONE:
329 return os << "CheckNone";
330 case STRING_ADD_CHECK_LEFT:
331 return os << "CheckLeft";
332 case STRING_ADD_CHECK_RIGHT:
333 return os << "CheckRight";
334 case STRING_ADD_CHECK_BOTH:
335 return os << "CheckBoth";
336 case STRING_ADD_CONVERT_LEFT:
337 return os << "ConvertLeft";
338 case STRING_ADD_CONVERT_RIGHT:
339 return os << "ConvertRight";
340 case STRING_ADD_CONVERT:
341 break;
342 }
343 UNREACHABLE();
344 return os;
345}
346
347
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400348void StringAddStub::PrintBaseName(std::ostream& os) const { // NOLINT
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000349 os << "StringAddStub_" << flags() << "_" << pretenure_flag();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000350}
351
352
353InlineCacheState CompareICStub::GetICState() const {
354 CompareICState::State state = Max(left(), right());
355 switch (state) {
356 case CompareICState::UNINITIALIZED:
357 return ::v8::internal::UNINITIALIZED;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000358 case CompareICState::BOOLEAN:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000359 case CompareICState::SMI:
360 case CompareICState::NUMBER:
361 case CompareICState::INTERNALIZED_STRING:
362 case CompareICState::STRING:
363 case CompareICState::UNIQUE_NAME:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000364 case CompareICState::RECEIVER:
365 case CompareICState::KNOWN_RECEIVER:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000366 return MONOMORPHIC;
367 case CompareICState::GENERIC:
368 return ::v8::internal::GENERIC;
369 }
370 UNREACHABLE();
371 return ::v8::internal::UNINITIALIZED;
372}
373
374
375Condition CompareICStub::GetCondition() const {
376 return CompareIC::ComputeCondition(op());
377}
378
379
380void CompareICStub::AddToSpecialCache(Handle<Code> new_object) {
381 DCHECK(*known_map_ != NULL);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100382 Isolate* isolate = new_object->GetIsolate();
383 Factory* factory = isolate->factory();
384 return Map::UpdateCodeCache(known_map_,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000385 strict() ?
386 factory->strict_compare_ic_string() :
387 factory->compare_ic_string(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100388 new_object);
389}
390
391
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000392bool CompareICStub::FindCodeInSpecialCache(Code** code_out) {
393 Factory* factory = isolate()->factory();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100394 Code::Flags flags = Code::ComputeFlags(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000395 GetCodeKind(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100396 UNINITIALIZED);
397 Handle<Object> probe(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000398 known_map_->FindInCodeCache(
399 strict() ?
400 *factory->strict_compare_ic_string() :
401 *factory->compare_ic_string(),
402 flags),
403 isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100404 if (probe->IsCode()) {
405 *code_out = Code::cast(*probe);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000406#ifdef DEBUG
407 CompareICStub decode((*code_out)->stub_key(), isolate());
408 DCHECK(op() == decode.op());
409 DCHECK(left() == decode.left());
410 DCHECK(right() == decode.right());
411 DCHECK(state() == decode.state());
412#endif
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100413 return true;
414 }
415 return false;
416}
417
418
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000419void CompareICStub::Generate(MacroAssembler* masm) {
420 switch (state()) {
421 case CompareICState::UNINITIALIZED:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100422 GenerateMiss(masm);
423 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000424 case CompareICState::BOOLEAN:
425 GenerateBooleans(masm);
426 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000427 case CompareICState::SMI:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100428 GenerateSmis(masm);
429 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000430 case CompareICState::NUMBER:
431 GenerateNumbers(masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100432 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000433 case CompareICState::STRING:
Ben Murdoch257744e2011-11-30 15:57:28 +0000434 GenerateStrings(masm);
435 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000436 case CompareICState::INTERNALIZED_STRING:
437 GenerateInternalizedStrings(masm);
Ben Murdoch257744e2011-11-30 15:57:28 +0000438 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000439 case CompareICState::UNIQUE_NAME:
440 GenerateUniqueNames(masm);
441 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000442 case CompareICState::RECEIVER:
443 GenerateReceivers(masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100444 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000445 case CompareICState::KNOWN_RECEIVER:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000446 DCHECK(*known_map_ != NULL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000447 GenerateKnownReceivers(masm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100448 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000449 case CompareICState::GENERIC:
450 GenerateGeneric(masm);
451 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100452 }
453}
454
455
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000456Handle<Code> TurboFanCodeStub::GenerateCode() {
457 const char* name = CodeStub::MajorName(MajorKey());
Ben Murdochda12d292016-06-02 14:46:10 +0100458 Zone zone(isolate()->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000459 CallInterfaceDescriptor descriptor(GetCallInterfaceDescriptor());
460 compiler::CodeStubAssembler assembler(isolate(), &zone, descriptor,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100461 GetCodeFlags(), name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000462 GenerateAssembly(&assembler);
463 return assembler.GenerateCode();
464}
465
Ben Murdochda12d292016-06-02 14:46:10 +0100466void AllocateHeapNumberStub::GenerateAssembly(
467 compiler::CodeStubAssembler* assembler) const {
468 typedef compiler::Node Node;
469
470 Node* result = assembler->AllocateHeapNumber();
471 assembler->Return(result);
472}
473
474void AllocateMutableHeapNumberStub::GenerateAssembly(
475 compiler::CodeStubAssembler* assembler) const {
476 typedef compiler::Node Node;
477
478 Node* result = assembler->Allocate(HeapNumber::kSize);
479 assembler->StoreMapNoWriteBarrier(
480 result,
481 assembler->HeapConstant(isolate()->factory()->mutable_heap_number_map()));
482 assembler->Return(result);
483}
484
485#define SIMD128_GEN_ASM(TYPE, Type, type, lane_count, lane_type) \
486 void Allocate##Type##Stub::GenerateAssembly( \
487 compiler::CodeStubAssembler* assembler) const { \
488 compiler::Node* result = assembler->Allocate( \
489 Simd128Value::kSize, compiler::CodeStubAssembler::kNone); \
490 compiler::Node* map_offset = \
491 assembler->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag); \
492 compiler::Node* map = assembler->IntPtrAdd(result, map_offset); \
493 assembler->StoreNoWriteBarrier( \
494 MachineRepresentation::kTagged, map, \
495 assembler->HeapConstant(isolate()->factory()->type##_map())); \
496 assembler->Return(result); \
497 }
498SIMD128_TYPES(SIMD128_GEN_ASM)
499#undef SIMD128_GEN_ASM
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000500
501void StringLengthStub::GenerateAssembly(
502 compiler::CodeStubAssembler* assembler) const {
503 compiler::Node* value = assembler->Parameter(0);
504 compiler::Node* string =
505 assembler->LoadObjectField(value, JSValue::kValueOffset);
506 compiler::Node* result =
507 assembler->LoadObjectField(string, String::kLengthOffset);
508 assembler->Return(result);
509}
510
Ben Murdochda12d292016-06-02 14:46:10 +0100511void AddStub::GenerateAssembly(compiler::CodeStubAssembler* assembler) const {
512 typedef compiler::CodeStubAssembler::Label Label;
513 typedef compiler::Node Node;
514 typedef compiler::CodeStubAssembler::Variable Variable;
515
516 Node* context = assembler->Parameter(2);
517
518 // Shared entry for floating point addition.
519 Label do_fadd(assembler);
520 Variable var_fadd_lhs(assembler, MachineRepresentation::kFloat64),
521 var_fadd_rhs(assembler, MachineRepresentation::kFloat64);
522
523 // We might need to loop several times due to ToPrimitive, ToString and/or
524 // ToNumber conversions.
525 Variable var_lhs(assembler, MachineRepresentation::kTagged),
526 var_rhs(assembler, MachineRepresentation::kTagged);
527 Variable* loop_vars[2] = {&var_lhs, &var_rhs};
528 Label loop(assembler, 2, loop_vars);
529 var_lhs.Bind(assembler->Parameter(0));
530 var_rhs.Bind(assembler->Parameter(1));
531 assembler->Goto(&loop);
532 assembler->Bind(&loop);
533 {
534 // Load the current {lhs} and {rhs} values.
535 Node* lhs = var_lhs.value();
536 Node* rhs = var_rhs.value();
537
538 // Check if the {lhs} is a Smi or a HeapObject.
539 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
540 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
541
542 assembler->Bind(&if_lhsissmi);
543 {
544 // Check if the {rhs} is also a Smi.
545 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
546 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
547 &if_rhsisnotsmi);
548
549 assembler->Bind(&if_rhsissmi);
550 {
551 // Try fast Smi addition first.
552 Node* pair = assembler->SmiAddWithOverflow(lhs, rhs);
553 Node* overflow = assembler->Projection(1, pair);
554
555 // Check if the Smi additon overflowed.
556 Label if_overflow(assembler), if_notoverflow(assembler);
557 assembler->Branch(overflow, &if_overflow, &if_notoverflow);
558
559 assembler->Bind(&if_overflow);
560 {
561 var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs));
562 var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs));
563 assembler->Goto(&do_fadd);
564 }
565
566 assembler->Bind(&if_notoverflow);
567 assembler->Return(assembler->Projection(0, pair));
568 }
569
570 assembler->Bind(&if_rhsisnotsmi);
571 {
572 // Load the map of {rhs}.
573 Node* rhs_map = assembler->LoadObjectField(rhs, HeapObject::kMapOffset);
574
575 // Check if the {rhs} is a HeapNumber.
576 Label if_rhsisnumber(assembler),
577 if_rhsisnotnumber(assembler, Label::kDeferred);
578 Node* number_map = assembler->HeapNumberMapConstant();
579 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
580 &if_rhsisnumber, &if_rhsisnotnumber);
581
582 assembler->Bind(&if_rhsisnumber);
583 {
584 var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs));
585 var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
586 assembler->Goto(&do_fadd);
587 }
588
589 assembler->Bind(&if_rhsisnotnumber);
590 {
591 // Load the instance type of {rhs}.
592 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
593
594 // Check if the {rhs} is a String.
595 Label if_rhsisstring(assembler, Label::kDeferred),
596 if_rhsisnotstring(assembler, Label::kDeferred);
597 assembler->Branch(assembler->Int32LessThan(
598 rhs_instance_type,
599 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
600 &if_rhsisstring, &if_rhsisnotstring);
601
602 assembler->Bind(&if_rhsisstring);
603 {
604 // Convert {lhs}, which is a Smi, to a String and concatenate the
605 // resulting string with the String {rhs}.
606 Callable callable = CodeFactory::StringAdd(
607 assembler->isolate(), STRING_ADD_CONVERT_LEFT, NOT_TENURED);
608 assembler->TailCallStub(callable, context, lhs, rhs);
609 }
610
611 assembler->Bind(&if_rhsisnotstring);
612 {
613 // Check if {rhs} is a JSReceiver.
614 Label if_rhsisreceiver(assembler, Label::kDeferred),
615 if_rhsisnotreceiver(assembler, Label::kDeferred);
616 assembler->Branch(
617 assembler->Int32LessThanOrEqual(
618 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
619 rhs_instance_type),
620 &if_rhsisreceiver, &if_rhsisnotreceiver);
621
622 assembler->Bind(&if_rhsisreceiver);
623 {
624 // Convert {rhs} to a primitive first passing no hint.
625 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
626 var_rhs.Bind(
627 assembler->CallRuntime(Runtime::kToPrimitive, context, rhs));
628 assembler->Goto(&loop);
629 }
630
631 assembler->Bind(&if_rhsisnotreceiver);
632 {
633 // Convert {rhs} to a Number first.
634 Callable callable =
635 CodeFactory::NonNumberToNumber(assembler->isolate());
636 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
637 assembler->Goto(&loop);
638 }
639 }
640 }
641 }
642 }
643
644 assembler->Bind(&if_lhsisnotsmi);
645 {
646 // Load the map and instance type of {lhs}.
647 Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
648
649 // Check if {lhs} is a String.
650 Label if_lhsisstring(assembler), if_lhsisnotstring(assembler);
651 assembler->Branch(assembler->Int32LessThan(
652 lhs_instance_type,
653 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
654 &if_lhsisstring, &if_lhsisnotstring);
655
656 assembler->Bind(&if_lhsisstring);
657 {
658 // Convert {rhs} to a String (using the sequence of ToPrimitive with
659 // no hint followed by ToString) and concatenate the strings.
660 Callable callable = CodeFactory::StringAdd(
661 assembler->isolate(), STRING_ADD_CONVERT_RIGHT, NOT_TENURED);
662 assembler->TailCallStub(callable, context, lhs, rhs);
663 }
664
665 assembler->Bind(&if_lhsisnotstring);
666 {
667 // Check if {rhs} is a Smi.
668 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
669 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
670 &if_rhsisnotsmi);
671
672 assembler->Bind(&if_rhsissmi);
673 {
674 // Check if {lhs} is a Number.
675 Label if_lhsisnumber(assembler),
676 if_lhsisnotnumber(assembler, Label::kDeferred);
677 assembler->Branch(assembler->Word32Equal(
678 lhs_instance_type,
679 assembler->Int32Constant(HEAP_NUMBER_TYPE)),
680 &if_lhsisnumber, &if_lhsisnotnumber);
681
682 assembler->Bind(&if_lhsisnumber);
683 {
684 // The {lhs} is a HeapNumber, the {rhs} is a Smi, just add them.
685 var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
686 var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs));
687 assembler->Goto(&do_fadd);
688 }
689
690 assembler->Bind(&if_lhsisnotnumber);
691 {
692 // The {lhs} is neither a Number nor a String, and the {rhs} is a
693 // Smi.
694 Label if_lhsisreceiver(assembler, Label::kDeferred),
695 if_lhsisnotreceiver(assembler, Label::kDeferred);
696 assembler->Branch(
697 assembler->Int32LessThanOrEqual(
698 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
699 lhs_instance_type),
700 &if_lhsisreceiver, &if_lhsisnotreceiver);
701
702 assembler->Bind(&if_lhsisreceiver);
703 {
704 // Convert {lhs} to a primitive first passing no hint.
705 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
706 var_lhs.Bind(
707 assembler->CallRuntime(Runtime::kToPrimitive, context, lhs));
708 assembler->Goto(&loop);
709 }
710
711 assembler->Bind(&if_lhsisnotreceiver);
712 {
713 // Convert {lhs} to a Number first.
714 Callable callable =
715 CodeFactory::NonNumberToNumber(assembler->isolate());
716 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
717 assembler->Goto(&loop);
718 }
719 }
720 }
721
722 assembler->Bind(&if_rhsisnotsmi);
723 {
724 // Load the instance type of {rhs}.
725 Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
726
727 // Check if {rhs} is a String.
728 Label if_rhsisstring(assembler), if_rhsisnotstring(assembler);
729 assembler->Branch(assembler->Int32LessThan(
730 rhs_instance_type,
731 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
732 &if_rhsisstring, &if_rhsisnotstring);
733
734 assembler->Bind(&if_rhsisstring);
735 {
736 // Convert {lhs} to a String (using the sequence of ToPrimitive with
737 // no hint followed by ToString) and concatenate the strings.
738 Callable callable = CodeFactory::StringAdd(
739 assembler->isolate(), STRING_ADD_CONVERT_LEFT, NOT_TENURED);
740 assembler->TailCallStub(callable, context, lhs, rhs);
741 }
742
743 assembler->Bind(&if_rhsisnotstring);
744 {
745 // Check if {lhs} is a HeapNumber.
746 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler);
747 assembler->Branch(assembler->Word32Equal(
748 lhs_instance_type,
749 assembler->Int32Constant(HEAP_NUMBER_TYPE)),
750 &if_lhsisnumber, &if_lhsisnotnumber);
751
752 assembler->Bind(&if_lhsisnumber);
753 {
754 // Check if {rhs} is also a HeapNumber.
755 Label if_rhsisnumber(assembler),
756 if_rhsisnotnumber(assembler, Label::kDeferred);
757 assembler->Branch(assembler->Word32Equal(
758 rhs_instance_type,
759 assembler->Int32Constant(HEAP_NUMBER_TYPE)),
760 &if_rhsisnumber, &if_rhsisnotnumber);
761
762 assembler->Bind(&if_rhsisnumber);
763 {
764 // Perform a floating point addition.
765 var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
766 var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
767 assembler->Goto(&do_fadd);
768 }
769
770 assembler->Bind(&if_rhsisnotnumber);
771 {
772 // Check if {rhs} is a JSReceiver.
773 Label if_rhsisreceiver(assembler, Label::kDeferred),
774 if_rhsisnotreceiver(assembler, Label::kDeferred);
775 assembler->Branch(
776 assembler->Int32LessThanOrEqual(
777 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
778 rhs_instance_type),
779 &if_rhsisreceiver, &if_rhsisnotreceiver);
780
781 assembler->Bind(&if_rhsisreceiver);
782 {
783 // Convert {rhs} to a primitive first passing no hint.
784 // TODO(bmeurer): Hook up ToPrimitiveStub here too.
785 var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
786 context, rhs));
787 assembler->Goto(&loop);
788 }
789
790 assembler->Bind(&if_rhsisnotreceiver);
791 {
792 // Convert {rhs} to a Number first.
793 Callable callable =
794 CodeFactory::NonNumberToNumber(assembler->isolate());
795 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
796 assembler->Goto(&loop);
797 }
798 }
799 }
800
801 assembler->Bind(&if_lhsisnotnumber);
802 {
803 // Check if {lhs} is a JSReceiver.
804 Label if_lhsisreceiver(assembler, Label::kDeferred),
805 if_lhsisnotreceiver(assembler);
806 assembler->Branch(
807 assembler->Int32LessThanOrEqual(
808 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
809 lhs_instance_type),
810 &if_lhsisreceiver, &if_lhsisnotreceiver);
811
812 assembler->Bind(&if_lhsisreceiver);
813 {
814 // Convert {lhs} to a primitive first passing no hint.
815 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
816 var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
817 context, lhs));
818 assembler->Goto(&loop);
819 }
820
821 assembler->Bind(&if_lhsisnotreceiver);
822 {
823 // Check if {rhs} is a JSReceiver.
824 Label if_rhsisreceiver(assembler, Label::kDeferred),
825 if_rhsisnotreceiver(assembler, Label::kDeferred);
826 assembler->Branch(
827 assembler->Int32LessThanOrEqual(
828 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
829 rhs_instance_type),
830 &if_rhsisreceiver, &if_rhsisnotreceiver);
831
832 assembler->Bind(&if_rhsisreceiver);
833 {
834 // Convert {rhs} to a primitive first passing no hint.
835 // TODO(bmeurer): Hook up ToPrimitiveStub here too.
836 var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
837 context, rhs));
838 assembler->Goto(&loop);
839 }
840
841 assembler->Bind(&if_rhsisnotreceiver);
842 {
843 // Convert {lhs} to a Number first.
844 Callable callable =
845 CodeFactory::NonNumberToNumber(assembler->isolate());
846 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
847 assembler->Goto(&loop);
848 }
849 }
850 }
851 }
852 }
853 }
854 }
855 }
856
857 assembler->Bind(&do_fadd);
858 {
859 Node* lhs_value = var_fadd_lhs.value();
860 Node* rhs_value = var_fadd_rhs.value();
861 Node* value = assembler->Float64Add(lhs_value, rhs_value);
862 Node* result = assembler->ChangeFloat64ToTagged(value);
863 assembler->Return(result);
864 }
865}
866
867void SubtractStub::GenerateAssembly(
868 compiler::CodeStubAssembler* assembler) const {
869 typedef compiler::CodeStubAssembler::Label Label;
870 typedef compiler::Node Node;
871 typedef compiler::CodeStubAssembler::Variable Variable;
872
873 Node* context = assembler->Parameter(2);
874
875 // Shared entry for floating point subtraction.
876 Label do_fsub(assembler);
877 Variable var_fsub_lhs(assembler, MachineRepresentation::kFloat64),
878 var_fsub_rhs(assembler, MachineRepresentation::kFloat64);
879
880 // We might need to loop several times due to ToPrimitive and/or ToNumber
881 // conversions.
882 Variable var_lhs(assembler, MachineRepresentation::kTagged),
883 var_rhs(assembler, MachineRepresentation::kTagged);
884 Variable* loop_vars[2] = {&var_lhs, &var_rhs};
885 Label loop(assembler, 2, loop_vars);
886 var_lhs.Bind(assembler->Parameter(0));
887 var_rhs.Bind(assembler->Parameter(1));
888 assembler->Goto(&loop);
889 assembler->Bind(&loop);
890 {
891 // Load the current {lhs} and {rhs} values.
892 Node* lhs = var_lhs.value();
893 Node* rhs = var_rhs.value();
894
895 // Check if the {lhs} is a Smi or a HeapObject.
896 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
897 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
898
899 assembler->Bind(&if_lhsissmi);
900 {
901 // Check if the {rhs} is also a Smi.
902 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
903 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
904 &if_rhsisnotsmi);
905
906 assembler->Bind(&if_rhsissmi);
907 {
908 // Try a fast Smi subtraction first.
909 Node* pair = assembler->SmiSubWithOverflow(lhs, rhs);
910 Node* overflow = assembler->Projection(1, pair);
911
912 // Check if the Smi subtraction overflowed.
913 Label if_overflow(assembler), if_notoverflow(assembler);
914 assembler->Branch(overflow, &if_overflow, &if_notoverflow);
915
916 assembler->Bind(&if_overflow);
917 {
918 // The result doesn't fit into Smi range.
919 var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs));
920 var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs));
921 assembler->Goto(&do_fsub);
922 }
923
924 assembler->Bind(&if_notoverflow);
925 assembler->Return(assembler->Projection(0, pair));
926 }
927
928 assembler->Bind(&if_rhsisnotsmi);
929 {
930 // Load the map of the {rhs}.
931 Node* rhs_map = assembler->LoadMap(rhs);
932
933 // Check if {rhs} is a HeapNumber.
934 Label if_rhsisnumber(assembler),
935 if_rhsisnotnumber(assembler, Label::kDeferred);
936 Node* number_map = assembler->HeapNumberMapConstant();
937 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
938 &if_rhsisnumber, &if_rhsisnotnumber);
939
940 assembler->Bind(&if_rhsisnumber);
941 {
942 // Perform a floating point subtraction.
943 var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs));
944 var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
945 assembler->Goto(&do_fsub);
946 }
947
948 assembler->Bind(&if_rhsisnotnumber);
949 {
950 // Convert the {rhs} to a Number first.
951 Callable callable = CodeFactory::NonNumberToNumber(isolate());
952 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
953 assembler->Goto(&loop);
954 }
955 }
956 }
957
958 assembler->Bind(&if_lhsisnotsmi);
959 {
960 // Load the map of the {lhs}.
961 Node* lhs_map = assembler->LoadMap(lhs);
962
963 // Check if the {lhs} is a HeapNumber.
964 Label if_lhsisnumber(assembler),
965 if_lhsisnotnumber(assembler, Label::kDeferred);
966 Node* number_map = assembler->HeapNumberMapConstant();
967 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
968 &if_lhsisnumber, &if_lhsisnotnumber);
969
970 assembler->Bind(&if_lhsisnumber);
971 {
972 // Check if the {rhs} is a Smi.
973 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
974 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
975 &if_rhsisnotsmi);
976
977 assembler->Bind(&if_rhsissmi);
978 {
979 // Perform a floating point subtraction.
980 var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
981 var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs));
982 assembler->Goto(&do_fsub);
983 }
984
985 assembler->Bind(&if_rhsisnotsmi);
986 {
987 // Load the map of the {rhs}.
988 Node* rhs_map = assembler->LoadMap(rhs);
989
990 // Check if the {rhs} is a HeapNumber.
991 Label if_rhsisnumber(assembler),
992 if_rhsisnotnumber(assembler, Label::kDeferred);
993 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
994 &if_rhsisnumber, &if_rhsisnotnumber);
995
996 assembler->Bind(&if_rhsisnumber);
997 {
998 // Perform a floating point subtraction.
999 var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
1000 var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
1001 assembler->Goto(&do_fsub);
1002 }
1003
1004 assembler->Bind(&if_rhsisnotnumber);
1005 {
1006 // Convert the {rhs} to a Number first.
1007 Callable callable = CodeFactory::NonNumberToNumber(isolate());
1008 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
1009 assembler->Goto(&loop);
1010 }
1011 }
1012 }
1013
1014 assembler->Bind(&if_lhsisnotnumber);
1015 {
1016 // Convert the {lhs} to a Number first.
1017 Callable callable = CodeFactory::NonNumberToNumber(isolate());
1018 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
1019 assembler->Goto(&loop);
1020 }
1021 }
1022 }
1023
1024 assembler->Bind(&do_fsub);
1025 {
1026 Node* lhs_value = var_fsub_lhs.value();
1027 Node* rhs_value = var_fsub_rhs.value();
1028 Node* value = assembler->Float64Sub(lhs_value, rhs_value);
1029 Node* result = assembler->ChangeFloat64ToTagged(value);
1030 assembler->Return(result);
1031 }
1032}
1033
1034void BitwiseAndStub::GenerateAssembly(
1035 compiler::CodeStubAssembler* assembler) const {
1036 using compiler::Node;
1037
1038 Node* lhs = assembler->Parameter(0);
1039 Node* rhs = assembler->Parameter(1);
1040 Node* context = assembler->Parameter(2);
1041 Node* lhs_value = assembler->TruncateTaggedToWord32(context, lhs);
1042 Node* rhs_value = assembler->TruncateTaggedToWord32(context, rhs);
1043 Node* value = assembler->Word32And(lhs_value, rhs_value);
1044 Node* result = assembler->ChangeInt32ToTagged(value);
1045 assembler->Return(result);
1046}
1047
1048void BitwiseOrStub::GenerateAssembly(
1049 compiler::CodeStubAssembler* assembler) const {
1050 using compiler::Node;
1051
1052 Node* lhs = assembler->Parameter(0);
1053 Node* rhs = assembler->Parameter(1);
1054 Node* context = assembler->Parameter(2);
1055 Node* lhs_value = assembler->TruncateTaggedToWord32(context, lhs);
1056 Node* rhs_value = assembler->TruncateTaggedToWord32(context, rhs);
1057 Node* value = assembler->Word32Or(lhs_value, rhs_value);
1058 Node* result = assembler->ChangeInt32ToTagged(value);
1059 assembler->Return(result);
1060}
1061
1062void BitwiseXorStub::GenerateAssembly(
1063 compiler::CodeStubAssembler* assembler) const {
1064 using compiler::Node;
1065
1066 Node* lhs = assembler->Parameter(0);
1067 Node* rhs = assembler->Parameter(1);
1068 Node* context = assembler->Parameter(2);
1069 Node* lhs_value = assembler->TruncateTaggedToWord32(context, lhs);
1070 Node* rhs_value = assembler->TruncateTaggedToWord32(context, rhs);
1071 Node* value = assembler->Word32Xor(lhs_value, rhs_value);
1072 Node* result = assembler->ChangeInt32ToTagged(value);
1073 assembler->Return(result);
1074}
1075
1076namespace {
1077
1078enum RelationalComparisonMode {
1079 kLessThan,
1080 kLessThanOrEqual,
1081 kGreaterThan,
1082 kGreaterThanOrEqual
1083};
1084
1085void GenerateAbstractRelationalComparison(
1086 compiler::CodeStubAssembler* assembler, RelationalComparisonMode mode) {
1087 typedef compiler::CodeStubAssembler::Label Label;
1088 typedef compiler::Node Node;
1089 typedef compiler::CodeStubAssembler::Variable Variable;
1090
1091 Node* context = assembler->Parameter(2);
1092
1093 Label return_true(assembler), return_false(assembler);
1094
1095 // Shared entry for floating point comparison.
1096 Label do_fcmp(assembler);
1097 Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64),
1098 var_fcmp_rhs(assembler, MachineRepresentation::kFloat64);
1099
1100 // We might need to loop several times due to ToPrimitive and/or ToNumber
1101 // conversions.
1102 Variable var_lhs(assembler, MachineRepresentation::kTagged),
1103 var_rhs(assembler, MachineRepresentation::kTagged);
1104 Variable* loop_vars[2] = {&var_lhs, &var_rhs};
1105 Label loop(assembler, 2, loop_vars);
1106 var_lhs.Bind(assembler->Parameter(0));
1107 var_rhs.Bind(assembler->Parameter(1));
1108 assembler->Goto(&loop);
1109 assembler->Bind(&loop);
1110 {
1111 // Load the current {lhs} and {rhs} values.
1112 Node* lhs = var_lhs.value();
1113 Node* rhs = var_rhs.value();
1114
1115 // Check if the {lhs} is a Smi or a HeapObject.
1116 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
1117 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
1118
1119 assembler->Bind(&if_lhsissmi);
1120 {
1121 // Check if {rhs} is a Smi or a HeapObject.
1122 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
1123 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
1124 &if_rhsisnotsmi);
1125
1126 assembler->Bind(&if_rhsissmi);
1127 {
1128 // Both {lhs} and {rhs} are Smi, so just perform a fast Smi comparison.
1129 switch (mode) {
1130 case kLessThan:
1131 assembler->BranchIfSmiLessThan(lhs, rhs, &return_true,
1132 &return_false);
1133 break;
1134 case kLessThanOrEqual:
1135 assembler->BranchIfSmiLessThanOrEqual(lhs, rhs, &return_true,
1136 &return_false);
1137 break;
1138 case kGreaterThan:
1139 assembler->BranchIfSmiLessThan(rhs, lhs, &return_true,
1140 &return_false);
1141 break;
1142 case kGreaterThanOrEqual:
1143 assembler->BranchIfSmiLessThanOrEqual(rhs, lhs, &return_true,
1144 &return_false);
1145 break;
1146 }
1147 }
1148
1149 assembler->Bind(&if_rhsisnotsmi);
1150 {
1151 // Load the map of {rhs}.
1152 Node* rhs_map = assembler->LoadMap(rhs);
1153
1154 // Check if the {rhs} is a HeapNumber.
1155 Node* number_map = assembler->HeapNumberMapConstant();
1156 Label if_rhsisnumber(assembler),
1157 if_rhsisnotnumber(assembler, Label::kDeferred);
1158 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
1159 &if_rhsisnumber, &if_rhsisnotnumber);
1160
1161 assembler->Bind(&if_rhsisnumber);
1162 {
1163 // Convert the {lhs} and {rhs} to floating point values, and
1164 // perform a floating point comparison.
1165 var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs));
1166 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
1167 assembler->Goto(&do_fcmp);
1168 }
1169
1170 assembler->Bind(&if_rhsisnotnumber);
1171 {
1172 // Convert the {rhs} to a Number; we don't need to perform the
1173 // dedicated ToPrimitive(rhs, hint Number) operation, as the
1174 // ToNumber(rhs) will by itself already invoke ToPrimitive with
1175 // a Number hint.
1176 Callable callable =
1177 CodeFactory::NonNumberToNumber(assembler->isolate());
1178 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
1179 assembler->Goto(&loop);
1180 }
1181 }
1182 }
1183
1184 assembler->Bind(&if_lhsisnotsmi);
1185 {
1186 // Load the HeapNumber map for later comparisons.
1187 Node* number_map = assembler->HeapNumberMapConstant();
1188
1189 // Load the map of {lhs}.
1190 Node* lhs_map = assembler->LoadMap(lhs);
1191
1192 // Check if {rhs} is a Smi or a HeapObject.
1193 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
1194 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
1195 &if_rhsisnotsmi);
1196
1197 assembler->Bind(&if_rhsissmi);
1198 {
1199 // Check if the {lhs} is a HeapNumber.
1200 Label if_lhsisnumber(assembler),
1201 if_lhsisnotnumber(assembler, Label::kDeferred);
1202 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
1203 &if_lhsisnumber, &if_lhsisnotnumber);
1204
1205 assembler->Bind(&if_lhsisnumber);
1206 {
1207 // Convert the {lhs} and {rhs} to floating point values, and
1208 // perform a floating point comparison.
1209 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
1210 var_fcmp_rhs.Bind(assembler->SmiToFloat64(rhs));
1211 assembler->Goto(&do_fcmp);
1212 }
1213
1214 assembler->Bind(&if_lhsisnotnumber);
1215 {
1216 // Convert the {lhs} to a Number; we don't need to perform the
1217 // dedicated ToPrimitive(lhs, hint Number) operation, as the
1218 // ToNumber(lhs) will by itself already invoke ToPrimitive with
1219 // a Number hint.
1220 Callable callable =
1221 CodeFactory::NonNumberToNumber(assembler->isolate());
1222 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
1223 assembler->Goto(&loop);
1224 }
1225 }
1226
1227 assembler->Bind(&if_rhsisnotsmi);
1228 {
1229 // Load the map of {rhs}.
1230 Node* rhs_map = assembler->LoadMap(rhs);
1231
1232 // Check if {lhs} is a HeapNumber.
1233 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler);
1234 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
1235 &if_lhsisnumber, &if_lhsisnotnumber);
1236
1237 assembler->Bind(&if_lhsisnumber);
1238 {
1239 // Check if {rhs} is also a HeapNumber.
1240 Label if_rhsisnumber(assembler),
1241 if_rhsisnotnumber(assembler, Label::kDeferred);
1242 assembler->Branch(assembler->WordEqual(lhs_map, rhs_map),
1243 &if_rhsisnumber, &if_rhsisnotnumber);
1244
1245 assembler->Bind(&if_rhsisnumber);
1246 {
1247 // Convert the {lhs} and {rhs} to floating point values, and
1248 // perform a floating point comparison.
1249 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
1250 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
1251 assembler->Goto(&do_fcmp);
1252 }
1253
1254 assembler->Bind(&if_rhsisnotnumber);
1255 {
1256 // Convert the {rhs} to a Number; we don't need to perform
1257 // dedicated ToPrimitive(rhs, hint Number) operation, as the
1258 // ToNumber(rhs) will by itself already invoke ToPrimitive with
1259 // a Number hint.
1260 Callable callable =
1261 CodeFactory::NonNumberToNumber(assembler->isolate());
1262 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
1263 assembler->Goto(&loop);
1264 }
1265 }
1266
1267 assembler->Bind(&if_lhsisnotnumber);
1268 {
1269 // Load the instance type of {lhs}.
1270 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map);
1271
1272 // Check if {lhs} is a String.
1273 Label if_lhsisstring(assembler),
1274 if_lhsisnotstring(assembler, Label::kDeferred);
1275 assembler->Branch(assembler->Int32LessThan(
1276 lhs_instance_type,
1277 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
1278 &if_lhsisstring, &if_lhsisnotstring);
1279
1280 assembler->Bind(&if_lhsisstring);
1281 {
1282 // Load the instance type of {rhs}.
1283 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
1284
1285 // Check if {rhs} is also a String.
1286 Label if_rhsisstring(assembler),
1287 if_rhsisnotstring(assembler, Label::kDeferred);
1288 assembler->Branch(assembler->Int32LessThan(
1289 rhs_instance_type, assembler->Int32Constant(
1290 FIRST_NONSTRING_TYPE)),
1291 &if_rhsisstring, &if_rhsisnotstring);
1292
1293 assembler->Bind(&if_rhsisstring);
1294 {
1295 // Both {lhs} and {rhs} are strings.
1296 switch (mode) {
1297 case kLessThan:
1298 assembler->TailCallStub(
1299 CodeFactory::StringLessThan(assembler->isolate()),
1300 context, lhs, rhs);
1301 break;
1302 case kLessThanOrEqual:
1303 assembler->TailCallStub(
1304 CodeFactory::StringLessThanOrEqual(assembler->isolate()),
1305 context, lhs, rhs);
1306 break;
1307 case kGreaterThan:
1308 assembler->TailCallStub(
1309 CodeFactory::StringGreaterThan(assembler->isolate()),
1310 context, lhs, rhs);
1311 break;
1312 case kGreaterThanOrEqual:
1313 assembler->TailCallStub(CodeFactory::StringGreaterThanOrEqual(
1314 assembler->isolate()),
1315 context, lhs, rhs);
1316 break;
1317 }
1318 }
1319
1320 assembler->Bind(&if_rhsisnotstring);
1321 {
1322 // The {lhs} is a String, while {rhs} is neither a Number nor a
1323 // String, so we need to call ToPrimitive(rhs, hint Number) if
1324 // {rhs} is a receiver or ToNumber(lhs) and ToNumber(rhs) in the
1325 // other cases.
1326 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
1327 Label if_rhsisreceiver(assembler, Label::kDeferred),
1328 if_rhsisnotreceiver(assembler, Label::kDeferred);
1329 assembler->Branch(
1330 assembler->Int32LessThanOrEqual(
1331 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
1332 rhs_instance_type),
1333 &if_rhsisreceiver, &if_rhsisnotreceiver);
1334
1335 assembler->Bind(&if_rhsisreceiver);
1336 {
1337 // Convert {rhs} to a primitive first passing Number hint.
1338 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
1339 var_rhs.Bind(assembler->CallRuntime(
1340 Runtime::kToPrimitive_Number, context, rhs));
1341 assembler->Goto(&loop);
1342 }
1343
1344 assembler->Bind(&if_rhsisnotreceiver);
1345 {
1346 // Convert both {lhs} and {rhs} to Number.
1347 Callable callable = CodeFactory::ToNumber(assembler->isolate());
1348 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
1349 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
1350 assembler->Goto(&loop);
1351 }
1352 }
1353 }
1354
1355 assembler->Bind(&if_lhsisnotstring);
1356 {
1357 // The {lhs} is neither a Number nor a String, so we need to call
1358 // ToPrimitive(lhs, hint Number) if {lhs} is a receiver or
1359 // ToNumber(lhs) and ToNumber(rhs) in the other cases.
1360 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
1361 Label if_lhsisreceiver(assembler, Label::kDeferred),
1362 if_lhsisnotreceiver(assembler, Label::kDeferred);
1363 assembler->Branch(
1364 assembler->Int32LessThanOrEqual(
1365 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
1366 lhs_instance_type),
1367 &if_lhsisreceiver, &if_lhsisnotreceiver);
1368
1369 assembler->Bind(&if_lhsisreceiver);
1370 {
1371 // Convert {lhs} to a primitive first passing Number hint.
1372 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
1373 var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive_Number,
1374 context, lhs));
1375 assembler->Goto(&loop);
1376 }
1377
1378 assembler->Bind(&if_lhsisnotreceiver);
1379 {
1380 // Convert both {lhs} and {rhs} to Number.
1381 Callable callable = CodeFactory::ToNumber(assembler->isolate());
1382 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
1383 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
1384 assembler->Goto(&loop);
1385 }
1386 }
1387 }
1388 }
1389 }
1390 }
1391
1392 assembler->Bind(&do_fcmp);
1393 {
1394 // Load the {lhs} and {rhs} floating point values.
1395 Node* lhs = var_fcmp_lhs.value();
1396 Node* rhs = var_fcmp_rhs.value();
1397
1398 // Perform a fast floating point comparison.
1399 switch (mode) {
1400 case kLessThan:
1401 assembler->BranchIfFloat64LessThan(lhs, rhs, &return_true,
1402 &return_false);
1403 break;
1404 case kLessThanOrEqual:
1405 assembler->BranchIfFloat64LessThanOrEqual(lhs, rhs, &return_true,
1406 &return_false);
1407 break;
1408 case kGreaterThan:
1409 assembler->BranchIfFloat64GreaterThan(lhs, rhs, &return_true,
1410 &return_false);
1411 break;
1412 case kGreaterThanOrEqual:
1413 assembler->BranchIfFloat64GreaterThanOrEqual(lhs, rhs, &return_true,
1414 &return_false);
1415 break;
1416 }
1417 }
1418
1419 assembler->Bind(&return_true);
1420 assembler->Return(assembler->BooleanConstant(true));
1421
1422 assembler->Bind(&return_false);
1423 assembler->Return(assembler->BooleanConstant(false));
1424}
1425
1426enum ResultMode { kDontNegateResult, kNegateResult };
1427
1428void GenerateEqual_Same(compiler::CodeStubAssembler* assembler,
1429 compiler::Node* value,
1430 compiler::CodeStubAssembler::Label* if_equal,
1431 compiler::CodeStubAssembler::Label* if_notequal) {
1432 // In case of abstract or strict equality checks, we need additional checks
1433 // for NaN values because they are not considered equal, even if both the
1434 // left and the right hand side reference exactly the same value.
1435 // TODO(bmeurer): This seems to violate the SIMD.js specification, but it
1436 // seems to be what is tested in the current SIMD.js testsuite.
1437
1438 typedef compiler::CodeStubAssembler::Label Label;
1439 typedef compiler::Node Node;
1440
1441 // Check if {value} is a Smi or a HeapObject.
1442 Label if_valueissmi(assembler), if_valueisnotsmi(assembler);
1443 assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi,
1444 &if_valueisnotsmi);
1445
1446 assembler->Bind(&if_valueisnotsmi);
1447 {
1448 // Load the map of {value}.
1449 Node* value_map = assembler->LoadMap(value);
1450
1451 // Check if {value} (and therefore {rhs}) is a HeapNumber.
1452 Node* number_map = assembler->HeapNumberMapConstant();
1453 Label if_valueisnumber(assembler), if_valueisnotnumber(assembler);
1454 assembler->Branch(assembler->WordEqual(value_map, number_map),
1455 &if_valueisnumber, &if_valueisnotnumber);
1456
1457 assembler->Bind(&if_valueisnumber);
1458 {
1459 // Convert {value} (and therefore {rhs}) to floating point value.
1460 Node* value_value = assembler->LoadHeapNumberValue(value);
1461
1462 // Check if the HeapNumber value is a NaN.
1463 assembler->BranchIfFloat64IsNaN(value_value, if_notequal, if_equal);
1464 }
1465
1466 assembler->Bind(&if_valueisnotnumber);
1467 assembler->Goto(if_equal);
1468 }
1469
1470 assembler->Bind(&if_valueissmi);
1471 assembler->Goto(if_equal);
1472}
1473
1474void GenerateEqual_Simd128Value_HeapObject(
1475 compiler::CodeStubAssembler* assembler, compiler::Node* lhs,
1476 compiler::Node* lhs_map, compiler::Node* rhs, compiler::Node* rhs_map,
1477 compiler::CodeStubAssembler::Label* if_equal,
1478 compiler::CodeStubAssembler::Label* if_notequal) {
1479 typedef compiler::CodeStubAssembler::Label Label;
1480 typedef compiler::Node Node;
1481
1482 // Check if {lhs} and {rhs} have the same map.
1483 Label if_mapsame(assembler), if_mapnotsame(assembler);
1484 assembler->Branch(assembler->WordEqual(lhs_map, rhs_map), &if_mapsame,
1485 &if_mapnotsame);
1486
1487 assembler->Bind(&if_mapsame);
1488 {
1489 // Both {lhs} and {rhs} are Simd128Values with the same map, need special
1490 // handling for Float32x4 because of NaN comparisons.
1491 Label if_float32x4(assembler), if_notfloat32x4(assembler);
1492 Node* float32x4_map =
1493 assembler->HeapConstant(assembler->factory()->float32x4_map());
1494 assembler->Branch(assembler->WordEqual(lhs_map, float32x4_map),
1495 &if_float32x4, &if_notfloat32x4);
1496
1497 assembler->Bind(&if_float32x4);
1498 {
1499 // Both {lhs} and {rhs} are Float32x4, compare the lanes individually
1500 // using a floating point comparison.
1501 for (int offset = Float32x4::kValueOffset - kHeapObjectTag;
1502 offset < Float32x4::kSize - kHeapObjectTag;
1503 offset += sizeof(float)) {
1504 // Load the floating point values for {lhs} and {rhs}.
1505 Node* lhs_value = assembler->Load(MachineType::Float32(), lhs,
1506 assembler->IntPtrConstant(offset));
1507 Node* rhs_value = assembler->Load(MachineType::Float32(), rhs,
1508 assembler->IntPtrConstant(offset));
1509
1510 // Perform a floating point comparison.
1511 Label if_valueequal(assembler), if_valuenotequal(assembler);
1512 assembler->Branch(assembler->Float32Equal(lhs_value, rhs_value),
1513 &if_valueequal, &if_valuenotequal);
1514 assembler->Bind(&if_valuenotequal);
1515 assembler->Goto(if_notequal);
1516 assembler->Bind(&if_valueequal);
1517 }
1518
1519 // All 4 lanes match, {lhs} and {rhs} considered equal.
1520 assembler->Goto(if_equal);
1521 }
1522
1523 assembler->Bind(&if_notfloat32x4);
1524 {
1525 // For other Simd128Values we just perform a bitwise comparison.
1526 for (int offset = Simd128Value::kValueOffset - kHeapObjectTag;
1527 offset < Simd128Value::kSize - kHeapObjectTag;
1528 offset += kPointerSize) {
1529 // Load the word values for {lhs} and {rhs}.
1530 Node* lhs_value = assembler->Load(MachineType::Pointer(), lhs,
1531 assembler->IntPtrConstant(offset));
1532 Node* rhs_value = assembler->Load(MachineType::Pointer(), rhs,
1533 assembler->IntPtrConstant(offset));
1534
1535 // Perform a bitwise word-comparison.
1536 Label if_valueequal(assembler), if_valuenotequal(assembler);
1537 assembler->Branch(assembler->WordEqual(lhs_value, rhs_value),
1538 &if_valueequal, &if_valuenotequal);
1539 assembler->Bind(&if_valuenotequal);
1540 assembler->Goto(if_notequal);
1541 assembler->Bind(&if_valueequal);
1542 }
1543
1544 // Bitwise comparison succeeded, {lhs} and {rhs} considered equal.
1545 assembler->Goto(if_equal);
1546 }
1547 }
1548
1549 assembler->Bind(&if_mapnotsame);
1550 assembler->Goto(if_notequal);
1551}
1552
1553// ES6 section 7.2.12 Abstract Equality Comparison
1554void GenerateEqual(compiler::CodeStubAssembler* assembler, ResultMode mode) {
1555 // This is a slightly optimized version of Object::Equals represented as
1556 // scheduled TurboFan graph utilizing the CodeStubAssembler. Whenever you
1557 // change something functionality wise in here, remember to update the
1558 // Object::Equals method as well.
1559 typedef compiler::CodeStubAssembler::Label Label;
1560 typedef compiler::Node Node;
1561 typedef compiler::CodeStubAssembler::Variable Variable;
1562
1563 Node* context = assembler->Parameter(2);
1564
1565 Label if_equal(assembler), if_notequal(assembler);
1566
1567 // Shared entry for floating point comparison.
1568 Label do_fcmp(assembler);
1569 Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64),
1570 var_fcmp_rhs(assembler, MachineRepresentation::kFloat64);
1571
1572 // We might need to loop several times due to ToPrimitive and/or ToNumber
1573 // conversions.
1574 Variable var_lhs(assembler, MachineRepresentation::kTagged),
1575 var_rhs(assembler, MachineRepresentation::kTagged);
1576 Variable* loop_vars[2] = {&var_lhs, &var_rhs};
1577 Label loop(assembler, 2, loop_vars);
1578 var_lhs.Bind(assembler->Parameter(0));
1579 var_rhs.Bind(assembler->Parameter(1));
1580 assembler->Goto(&loop);
1581 assembler->Bind(&loop);
1582 {
1583 // Load the current {lhs} and {rhs} values.
1584 Node* lhs = var_lhs.value();
1585 Node* rhs = var_rhs.value();
1586
1587 // Check if {lhs} and {rhs} refer to the same object.
1588 Label if_same(assembler), if_notsame(assembler);
1589 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
1590
1591 assembler->Bind(&if_same);
1592 {
1593 // The {lhs} and {rhs} reference the exact same value, yet we need special
1594 // treatment for HeapNumber, as NaN is not equal to NaN.
1595 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal);
1596 }
1597
1598 assembler->Bind(&if_notsame);
1599 {
1600 // Check if {lhs} is a Smi or a HeapObject.
1601 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
1602 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi,
1603 &if_lhsisnotsmi);
1604
1605 assembler->Bind(&if_lhsissmi);
1606 {
1607 // Check if {rhs} is a Smi or a HeapObject.
1608 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
1609 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
1610 &if_rhsisnotsmi);
1611
1612 assembler->Bind(&if_rhsissmi);
1613 assembler->Goto(&if_notequal);
1614
1615 assembler->Bind(&if_rhsisnotsmi);
1616 {
1617 // Load the map of {rhs}.
1618 Node* rhs_map = assembler->LoadMap(rhs);
1619
1620 // Check if {rhs} is a HeapNumber.
1621 Node* number_map = assembler->HeapNumberMapConstant();
1622 Label if_rhsisnumber(assembler),
1623 if_rhsisnotnumber(assembler, Label::kDeferred);
1624 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
1625 &if_rhsisnumber, &if_rhsisnotnumber);
1626
1627 assembler->Bind(&if_rhsisnumber);
1628 {
1629 // Convert {lhs} and {rhs} to floating point values, and
1630 // perform a floating point comparison.
1631 var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs));
1632 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
1633 assembler->Goto(&do_fcmp);
1634 }
1635
1636 assembler->Bind(&if_rhsisnotnumber);
1637 {
1638 // Load the instance type of the {rhs}.
1639 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
1640
1641 // Check if the {rhs} is a String.
1642 Label if_rhsisstring(assembler, Label::kDeferred),
1643 if_rhsisnotstring(assembler, Label::kDeferred);
1644 assembler->Branch(assembler->Int32LessThan(
1645 rhs_instance_type, assembler->Int32Constant(
1646 FIRST_NONSTRING_TYPE)),
1647 &if_rhsisstring, &if_rhsisnotstring);
1648
1649 assembler->Bind(&if_rhsisstring);
1650 {
1651 // Convert the {rhs} to a Number.
1652 Callable callable =
1653 CodeFactory::StringToNumber(assembler->isolate());
1654 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
1655 assembler->Goto(&loop);
1656 }
1657
1658 assembler->Bind(&if_rhsisnotstring);
1659 {
1660 // Check if the {rhs} is a Boolean.
1661 Node* boolean_map = assembler->BooleanMapConstant();
1662 Label if_rhsisboolean(assembler, Label::kDeferred),
1663 if_rhsisnotboolean(assembler, Label::kDeferred);
1664 assembler->Branch(assembler->WordEqual(rhs_map, boolean_map),
1665 &if_rhsisboolean, &if_rhsisnotboolean);
1666
1667 assembler->Bind(&if_rhsisboolean);
1668 {
1669 // The {rhs} is a Boolean, load its number value.
1670 var_rhs.Bind(
1671 assembler->LoadObjectField(rhs, Oddball::kToNumberOffset));
1672 assembler->Goto(&loop);
1673 }
1674
1675 assembler->Bind(&if_rhsisnotboolean);
1676 {
1677 // Check if the {rhs} is a Receiver.
1678 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
1679 Label if_rhsisreceiver(assembler, Label::kDeferred),
1680 if_rhsisnotreceiver(assembler, Label::kDeferred);
1681 assembler->Branch(
1682 assembler->Int32LessThanOrEqual(
1683 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
1684 rhs_instance_type),
1685 &if_rhsisreceiver, &if_rhsisnotreceiver);
1686
1687 assembler->Bind(&if_rhsisreceiver);
1688 {
1689 // Convert {rhs} to a primitive first (passing no hint).
1690 // TODO(bmeurer): Hook up ToPrimitiveStub here once it exists.
1691 var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
1692 context, rhs));
1693 assembler->Goto(&loop);
1694 }
1695
1696 assembler->Bind(&if_rhsisnotreceiver);
1697 assembler->Goto(&if_notequal);
1698 }
1699 }
1700 }
1701 }
1702 }
1703
1704 assembler->Bind(&if_lhsisnotsmi);
1705 {
1706 // Check if {rhs} is a Smi or a HeapObject.
1707 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
1708 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
1709 &if_rhsisnotsmi);
1710
1711 assembler->Bind(&if_rhsissmi);
1712 {
1713 // The {lhs} is a HeapObject and the {rhs} is a Smi; swapping {lhs}
1714 // and {rhs} is not observable and doesn't matter for the result, so
1715 // we can just swap them and use the Smi handling above (for {lhs}
1716 // being a Smi).
1717 var_lhs.Bind(rhs);
1718 var_rhs.Bind(lhs);
1719 assembler->Goto(&loop);
1720 }
1721
1722 assembler->Bind(&if_rhsisnotsmi);
1723 {
1724 Label if_lhsisstring(assembler), if_lhsisnumber(assembler),
1725 if_lhsissymbol(assembler), if_lhsissimd128value(assembler),
1726 if_lhsisoddball(assembler), if_lhsisreceiver(assembler);
1727
1728 // Both {lhs} and {rhs} are HeapObjects, load their maps
1729 // and their instance types.
1730 Node* lhs_map = assembler->LoadMap(lhs);
1731 Node* rhs_map = assembler->LoadMap(rhs);
1732
1733 // Load the instance types of {lhs} and {rhs}.
1734 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map);
1735 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
1736
1737 // Dispatch based on the instance type of {lhs}.
1738 size_t const kNumCases = FIRST_NONSTRING_TYPE + 4;
1739 Label* case_labels[kNumCases];
1740 int32_t case_values[kNumCases];
1741 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) {
1742 case_labels[i] = new Label(assembler);
1743 case_values[i] = i;
1744 }
1745 case_labels[FIRST_NONSTRING_TYPE + 0] = &if_lhsisnumber;
1746 case_values[FIRST_NONSTRING_TYPE + 0] = HEAP_NUMBER_TYPE;
1747 case_labels[FIRST_NONSTRING_TYPE + 1] = &if_lhsissymbol;
1748 case_values[FIRST_NONSTRING_TYPE + 1] = SYMBOL_TYPE;
1749 case_labels[FIRST_NONSTRING_TYPE + 2] = &if_lhsissimd128value;
1750 case_values[FIRST_NONSTRING_TYPE + 2] = SIMD128_VALUE_TYPE;
1751 case_labels[FIRST_NONSTRING_TYPE + 3] = &if_lhsisoddball;
1752 case_values[FIRST_NONSTRING_TYPE + 3] = ODDBALL_TYPE;
1753 assembler->Switch(lhs_instance_type, &if_lhsisreceiver, case_values,
1754 case_labels, arraysize(case_values));
1755 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) {
1756 assembler->Bind(case_labels[i]);
1757 assembler->Goto(&if_lhsisstring);
1758 delete case_labels[i];
1759 }
1760
1761 assembler->Bind(&if_lhsisstring);
1762 {
1763 // Check if {rhs} is also a String.
1764 Label if_rhsisstring(assembler),
1765 if_rhsisnotstring(assembler, Label::kDeferred);
1766 assembler->Branch(assembler->Int32LessThan(
1767 rhs_instance_type, assembler->Int32Constant(
1768 FIRST_NONSTRING_TYPE)),
1769 &if_rhsisstring, &if_rhsisnotstring);
1770
1771 assembler->Bind(&if_rhsisstring);
1772 {
1773 // Both {lhs} and {rhs} are of type String, just do the
1774 // string comparison then.
1775 Callable callable =
1776 (mode == kDontNegateResult)
1777 ? CodeFactory::StringEqual(assembler->isolate())
1778 : CodeFactory::StringNotEqual(assembler->isolate());
1779 assembler->TailCallStub(callable, context, lhs, rhs);
1780 }
1781
1782 assembler->Bind(&if_rhsisnotstring);
1783 {
1784 // The {lhs} is a String and the {rhs} is some other HeapObject.
1785 // Swapping {lhs} and {rhs} is not observable and doesn't matter
1786 // for the result, so we can just swap them and use the String
1787 // handling below (for {rhs} being a String).
1788 var_lhs.Bind(rhs);
1789 var_rhs.Bind(lhs);
1790 assembler->Goto(&loop);
1791 }
1792 }
1793
1794 assembler->Bind(&if_lhsisnumber);
1795 {
1796 // Check if {rhs} is also a HeapNumber.
1797 Label if_rhsisnumber(assembler),
1798 if_rhsisnotnumber(assembler, Label::kDeferred);
1799 assembler->Branch(
1800 assembler->Word32Equal(lhs_instance_type, rhs_instance_type),
1801 &if_rhsisnumber, &if_rhsisnotnumber);
1802
1803 assembler->Bind(&if_rhsisnumber);
1804 {
1805 // Convert {lhs} and {rhs} to floating point values, and
1806 // perform a floating point comparison.
1807 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
1808 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
1809 assembler->Goto(&do_fcmp);
1810 }
1811
1812 assembler->Bind(&if_rhsisnotnumber);
1813 {
1814 // The {lhs} is a Number, the {rhs} is some other HeapObject.
1815 Label if_rhsisstring(assembler, Label::kDeferred),
1816 if_rhsisnotstring(assembler);
1817 assembler->Branch(
1818 assembler->Int32LessThan(
1819 rhs_instance_type,
1820 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
1821 &if_rhsisstring, &if_rhsisnotstring);
1822
1823 assembler->Bind(&if_rhsisstring);
1824 {
1825 // The {rhs} is a String and the {lhs} is a HeapNumber; we need
1826 // to convert the {rhs} to a Number and compare the output to
1827 // the Number on the {lhs}.
1828 Callable callable =
1829 CodeFactory::StringToNumber(assembler->isolate());
1830 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
1831 assembler->Goto(&loop);
1832 }
1833
1834 assembler->Bind(&if_rhsisnotstring);
1835 {
1836 // Check if the {rhs} is a JSReceiver.
1837 Label if_rhsisreceiver(assembler, Label::kDeferred),
1838 if_rhsisnotreceiver(assembler);
1839 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
1840 assembler->Branch(
1841 assembler->Int32LessThanOrEqual(
1842 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
1843 rhs_instance_type),
1844 &if_rhsisreceiver, &if_rhsisnotreceiver);
1845
1846 assembler->Bind(&if_rhsisreceiver);
1847 {
1848 // The {lhs} is a Primitive and the {rhs} is a JSReceiver.
1849 // Swapping {lhs} and {rhs} is not observable and doesn't
1850 // matter for the result, so we can just swap them and use
1851 // the JSReceiver handling below (for {lhs} being a
1852 // JSReceiver).
1853 var_lhs.Bind(rhs);
1854 var_rhs.Bind(lhs);
1855 assembler->Goto(&loop);
1856 }
1857
1858 assembler->Bind(&if_rhsisnotreceiver);
1859 {
1860 // Check if {rhs} is a Boolean.
1861 Label if_rhsisboolean(assembler),
1862 if_rhsisnotboolean(assembler);
1863 Node* boolean_map = assembler->BooleanMapConstant();
1864 assembler->Branch(assembler->WordEqual(rhs_map, boolean_map),
1865 &if_rhsisboolean, &if_rhsisnotboolean);
1866
1867 assembler->Bind(&if_rhsisboolean);
1868 {
1869 // The {rhs} is a Boolean, convert it to a Smi first.
1870 var_rhs.Bind(assembler->LoadObjectField(
1871 rhs, Oddball::kToNumberOffset));
1872 assembler->Goto(&loop);
1873 }
1874
1875 assembler->Bind(&if_rhsisnotboolean);
1876 assembler->Goto(&if_notequal);
1877 }
1878 }
1879 }
1880 }
1881
1882 assembler->Bind(&if_lhsisoddball);
1883 {
1884 // The {lhs} is an Oddball and {rhs} is some other HeapObject.
1885 Label if_lhsisboolean(assembler), if_lhsisnotboolean(assembler);
1886 Node* boolean_map = assembler->BooleanMapConstant();
1887 assembler->Branch(assembler->WordEqual(lhs_map, boolean_map),
1888 &if_lhsisboolean, &if_lhsisnotboolean);
1889
1890 assembler->Bind(&if_lhsisboolean);
1891 {
1892 // The {lhs} is a Boolean, check if {rhs} is also a Boolean.
1893 Label if_rhsisboolean(assembler), if_rhsisnotboolean(assembler);
1894 assembler->Branch(assembler->WordEqual(rhs_map, boolean_map),
1895 &if_rhsisboolean, &if_rhsisnotboolean);
1896
1897 assembler->Bind(&if_rhsisboolean);
1898 {
1899 // Both {lhs} and {rhs} are distinct Boolean values.
1900 assembler->Goto(&if_notequal);
1901 }
1902
1903 assembler->Bind(&if_rhsisnotboolean);
1904 {
1905 // Convert the {lhs} to a Number first.
1906 var_lhs.Bind(
1907 assembler->LoadObjectField(lhs, Oddball::kToNumberOffset));
1908 assembler->Goto(&loop);
1909 }
1910 }
1911
1912 assembler->Bind(&if_lhsisnotboolean);
1913 {
1914 // The {lhs} is either Null or Undefined; check if the {rhs} is
1915 // undetectable (i.e. either also Null or Undefined or some
1916 // undetectable JSReceiver).
1917 Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map);
1918 assembler->BranchIfWord32Equal(
1919 assembler->Word32And(
1920 rhs_bitfield,
1921 assembler->Int32Constant(1 << Map::kIsUndetectable)),
1922 assembler->Int32Constant(0), &if_notequal, &if_equal);
1923 }
1924 }
1925
1926 assembler->Bind(&if_lhsissymbol);
1927 {
1928 // Check if the {rhs} is a JSReceiver.
1929 Label if_rhsisreceiver(assembler, Label::kDeferred),
1930 if_rhsisnotreceiver(assembler);
1931 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
1932 assembler->Branch(
1933 assembler->Int32LessThanOrEqual(
1934 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
1935 rhs_instance_type),
1936 &if_rhsisreceiver, &if_rhsisnotreceiver);
1937
1938 assembler->Bind(&if_rhsisreceiver);
1939 {
1940 // The {lhs} is a Primitive and the {rhs} is a JSReceiver.
1941 // Swapping {lhs} and {rhs} is not observable and doesn't
1942 // matter for the result, so we can just swap them and use
1943 // the JSReceiver handling below (for {lhs} being a JSReceiver).
1944 var_lhs.Bind(rhs);
1945 var_rhs.Bind(lhs);
1946 assembler->Goto(&loop);
1947 }
1948
1949 assembler->Bind(&if_rhsisnotreceiver);
1950 {
1951 // The {rhs} is not a JSReceiver and also not the same Symbol
1952 // as the {lhs}, so this is equality check is considered false.
1953 assembler->Goto(&if_notequal);
1954 }
1955 }
1956
1957 assembler->Bind(&if_lhsissimd128value);
1958 {
1959 // Check if the {rhs} is also a Simd128Value.
1960 Label if_rhsissimd128value(assembler),
1961 if_rhsisnotsimd128value(assembler);
1962 assembler->Branch(
1963 assembler->Word32Equal(lhs_instance_type, rhs_instance_type),
1964 &if_rhsissimd128value, &if_rhsisnotsimd128value);
1965
1966 assembler->Bind(&if_rhsissimd128value);
1967 {
1968 // Both {lhs} and {rhs} is a Simd128Value.
1969 GenerateEqual_Simd128Value_HeapObject(assembler, lhs, lhs_map,
1970 rhs, rhs_map, &if_equal,
1971 &if_notequal);
1972 }
1973
1974 assembler->Bind(&if_rhsisnotsimd128value);
1975 {
1976 // Check if the {rhs} is a JSReceiver.
1977 Label if_rhsisreceiver(assembler, Label::kDeferred),
1978 if_rhsisnotreceiver(assembler);
1979 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
1980 assembler->Branch(
1981 assembler->Int32LessThanOrEqual(
1982 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
1983 rhs_instance_type),
1984 &if_rhsisreceiver, &if_rhsisnotreceiver);
1985
1986 assembler->Bind(&if_rhsisreceiver);
1987 {
1988 // The {lhs} is a Primitive and the {rhs} is a JSReceiver.
1989 // Swapping {lhs} and {rhs} is not observable and doesn't
1990 // matter for the result, so we can just swap them and use
1991 // the JSReceiver handling below (for {lhs} being a JSReceiver).
1992 var_lhs.Bind(rhs);
1993 var_rhs.Bind(lhs);
1994 assembler->Goto(&loop);
1995 }
1996
1997 assembler->Bind(&if_rhsisnotreceiver);
1998 {
1999 // The {rhs} is some other Primitive.
2000 assembler->Goto(&if_notequal);
2001 }
2002 }
2003 }
2004
2005 assembler->Bind(&if_lhsisreceiver);
2006 {
2007 // Check if the {rhs} is also a JSReceiver.
2008 Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler);
2009 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
2010 assembler->Branch(
2011 assembler->Int32LessThanOrEqual(
2012 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
2013 rhs_instance_type),
2014 &if_rhsisreceiver, &if_rhsisnotreceiver);
2015
2016 assembler->Bind(&if_rhsisreceiver);
2017 {
2018 // Both {lhs} and {rhs} are different JSReceiver references, so
2019 // this cannot be considered equal.
2020 assembler->Goto(&if_notequal);
2021 }
2022
2023 assembler->Bind(&if_rhsisnotreceiver);
2024 {
2025 // Check if {rhs} is Null or Undefined (an undetectable check
2026 // is sufficient here, since we already know that {rhs} is not
2027 // a JSReceiver).
2028 Label if_rhsisundetectable(assembler),
2029 if_rhsisnotundetectable(assembler, Label::kDeferred);
2030 Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map);
2031 assembler->BranchIfWord32Equal(
2032 assembler->Word32And(
2033 rhs_bitfield,
2034 assembler->Int32Constant(1 << Map::kIsUndetectable)),
2035 assembler->Int32Constant(0), &if_rhsisnotundetectable,
2036 &if_rhsisundetectable);
2037
2038 assembler->Bind(&if_rhsisundetectable);
2039 {
2040 // Check if {lhs} is an undetectable JSReceiver.
2041 Node* lhs_bitfield = assembler->LoadMapBitField(lhs_map);
2042 assembler->BranchIfWord32Equal(
2043 assembler->Word32And(
2044 lhs_bitfield,
2045 assembler->Int32Constant(1 << Map::kIsUndetectable)),
2046 assembler->Int32Constant(0), &if_notequal, &if_equal);
2047 }
2048
2049 assembler->Bind(&if_rhsisnotundetectable);
2050 {
2051 // The {rhs} is some Primitive different from Null and
2052 // Undefined, need to convert {lhs} to Primitive first.
2053 // TODO(bmeurer): Hook up ToPrimitiveStub here once it exists.
2054 var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
2055 context, lhs));
2056 assembler->Goto(&loop);
2057 }
2058 }
2059 }
2060 }
2061 }
2062 }
2063 }
2064
2065 assembler->Bind(&do_fcmp);
2066 {
2067 // Load the {lhs} and {rhs} floating point values.
2068 Node* lhs = var_fcmp_lhs.value();
2069 Node* rhs = var_fcmp_rhs.value();
2070
2071 // Perform a fast floating point comparison.
2072 assembler->BranchIfFloat64Equal(lhs, rhs, &if_equal, &if_notequal);
2073 }
2074
2075 assembler->Bind(&if_equal);
2076 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult));
2077
2078 assembler->Bind(&if_notequal);
2079 assembler->Return(assembler->BooleanConstant(mode == kNegateResult));
2080}
2081
2082void GenerateStrictEqual(compiler::CodeStubAssembler* assembler,
2083 ResultMode mode) {
2084 // Here's pseudo-code for the algorithm below in case of kDontNegateResult
2085 // mode; for kNegateResult mode we properly negate the result.
2086 //
2087 // if (lhs == rhs) {
2088 // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN;
2089 // return true;
2090 // }
2091 // if (!lhs->IsSmi()) {
2092 // if (lhs->IsHeapNumber()) {
2093 // if (rhs->IsSmi()) {
2094 // return Smi::cast(rhs)->value() == HeapNumber::cast(lhs)->value();
2095 // } else if (rhs->IsHeapNumber()) {
2096 // return HeapNumber::cast(rhs)->value() ==
2097 // HeapNumber::cast(lhs)->value();
2098 // } else {
2099 // return false;
2100 // }
2101 // } else {
2102 // if (rhs->IsSmi()) {
2103 // return false;
2104 // } else {
2105 // if (lhs->IsString()) {
2106 // if (rhs->IsString()) {
2107 // return %StringEqual(lhs, rhs);
2108 // } else {
2109 // return false;
2110 // }
2111 // } else if (lhs->IsSimd128()) {
2112 // if (rhs->IsSimd128()) {
2113 // return %StrictEqual(lhs, rhs);
2114 // }
2115 // } else {
2116 // return false;
2117 // }
2118 // }
2119 // }
2120 // } else {
2121 // if (rhs->IsSmi()) {
2122 // return false;
2123 // } else {
2124 // if (rhs->IsHeapNumber()) {
2125 // return Smi::cast(lhs)->value() == HeapNumber::cast(rhs)->value();
2126 // } else {
2127 // return false;
2128 // }
2129 // }
2130 // }
2131
2132 typedef compiler::CodeStubAssembler::Label Label;
2133 typedef compiler::Node Node;
2134
2135 Node* lhs = assembler->Parameter(0);
2136 Node* rhs = assembler->Parameter(1);
2137 Node* context = assembler->Parameter(2);
2138
2139 Label if_equal(assembler), if_notequal(assembler);
2140
2141 // Check if {lhs} and {rhs} refer to the same object.
2142 Label if_same(assembler), if_notsame(assembler);
2143 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
2144
2145 assembler->Bind(&if_same);
2146 {
2147 // The {lhs} and {rhs} reference the exact same value, yet we need special
2148 // treatment for HeapNumber, as NaN is not equal to NaN.
2149 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal);
2150 }
2151
2152 assembler->Bind(&if_notsame);
2153 {
2154 // The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber,
2155 // String and Simd128Value they can still be considered equal.
2156 Node* number_map = assembler->HeapNumberMapConstant();
2157
2158 // Check if {lhs} is a Smi or a HeapObject.
2159 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
2160 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
2161
2162 assembler->Bind(&if_lhsisnotsmi);
2163 {
2164 // Load the map of {lhs}.
2165 Node* lhs_map = assembler->LoadMap(lhs);
2166
2167 // Check if {lhs} is a HeapNumber.
2168 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler);
2169 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
2170 &if_lhsisnumber, &if_lhsisnotnumber);
2171
2172 assembler->Bind(&if_lhsisnumber);
2173 {
2174 // Check if {rhs} is a Smi or a HeapObject.
2175 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
2176 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
2177 &if_rhsisnotsmi);
2178
2179 assembler->Bind(&if_rhsissmi);
2180 {
2181 // Convert {lhs} and {rhs} to floating point values.
2182 Node* lhs_value = assembler->LoadHeapNumberValue(lhs);
2183 Node* rhs_value = assembler->SmiToFloat64(rhs);
2184
2185 // Perform a floating point comparison of {lhs} and {rhs}.
2186 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal,
2187 &if_notequal);
2188 }
2189
2190 assembler->Bind(&if_rhsisnotsmi);
2191 {
2192 // Load the map of {rhs}.
2193 Node* rhs_map = assembler->LoadMap(rhs);
2194
2195 // Check if {rhs} is also a HeapNumber.
2196 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler);
2197 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
2198 &if_rhsisnumber, &if_rhsisnotnumber);
2199
2200 assembler->Bind(&if_rhsisnumber);
2201 {
2202 // Convert {lhs} and {rhs} to floating point values.
2203 Node* lhs_value = assembler->LoadHeapNumberValue(lhs);
2204 Node* rhs_value = assembler->LoadHeapNumberValue(rhs);
2205
2206 // Perform a floating point comparison of {lhs} and {rhs}.
2207 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal,
2208 &if_notequal);
2209 }
2210
2211 assembler->Bind(&if_rhsisnotnumber);
2212 assembler->Goto(&if_notequal);
2213 }
2214 }
2215
2216 assembler->Bind(&if_lhsisnotnumber);
2217 {
2218 // Check if {rhs} is a Smi or a HeapObject.
2219 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
2220 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
2221 &if_rhsisnotsmi);
2222
2223 assembler->Bind(&if_rhsissmi);
2224 assembler->Goto(&if_notequal);
2225
2226 assembler->Bind(&if_rhsisnotsmi);
2227 {
2228 // Load the instance type of {lhs}.
2229 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map);
2230
2231 // Check if {lhs} is a String.
2232 Label if_lhsisstring(assembler), if_lhsisnotstring(assembler);
2233 assembler->Branch(assembler->Int32LessThan(
2234 lhs_instance_type,
2235 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
2236 &if_lhsisstring, &if_lhsisnotstring);
2237
2238 assembler->Bind(&if_lhsisstring);
2239 {
2240 // Load the instance type of {rhs}.
2241 Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
2242
2243 // Check if {rhs} is also a String.
2244 Label if_rhsisstring(assembler), if_rhsisnotstring(assembler);
2245 assembler->Branch(assembler->Int32LessThan(
2246 rhs_instance_type, assembler->Int32Constant(
2247 FIRST_NONSTRING_TYPE)),
2248 &if_rhsisstring, &if_rhsisnotstring);
2249
2250 assembler->Bind(&if_rhsisstring);
2251 {
2252 Callable callable =
2253 (mode == kDontNegateResult)
2254 ? CodeFactory::StringEqual(assembler->isolate())
2255 : CodeFactory::StringNotEqual(assembler->isolate());
2256 assembler->TailCallStub(callable, context, lhs, rhs);
2257 }
2258
2259 assembler->Bind(&if_rhsisnotstring);
2260 assembler->Goto(&if_notequal);
2261 }
2262
2263 assembler->Bind(&if_lhsisnotstring);
2264 {
2265 // Check if {lhs} is a Simd128Value.
2266 Label if_lhsissimd128value(assembler),
2267 if_lhsisnotsimd128value(assembler);
2268 assembler->Branch(assembler->Word32Equal(
2269 lhs_instance_type,
2270 assembler->Int32Constant(SIMD128_VALUE_TYPE)),
2271 &if_lhsissimd128value, &if_lhsisnotsimd128value);
2272
2273 assembler->Bind(&if_lhsissimd128value);
2274 {
2275 // Load the map of {rhs}.
2276 Node* rhs_map = assembler->LoadMap(rhs);
2277
2278 // Check if {rhs} is also a Simd128Value that is equal to {lhs}.
2279 GenerateEqual_Simd128Value_HeapObject(assembler, lhs, lhs_map,
2280 rhs, rhs_map, &if_equal,
2281 &if_notequal);
2282 }
2283
2284 assembler->Bind(&if_lhsisnotsimd128value);
2285 assembler->Goto(&if_notequal);
2286 }
2287 }
2288 }
2289 }
2290
2291 assembler->Bind(&if_lhsissmi);
2292 {
2293 // We already know that {lhs} and {rhs} are not reference equal, and {lhs}
2294 // is a Smi; so {lhs} and {rhs} can only be strictly equal if {rhs} is a
2295 // HeapNumber with an equal floating point value.
2296
2297 // Check if {rhs} is a Smi or a HeapObject.
2298 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
2299 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
2300 &if_rhsisnotsmi);
2301
2302 assembler->Bind(&if_rhsissmi);
2303 assembler->Goto(&if_notequal);
2304
2305 assembler->Bind(&if_rhsisnotsmi);
2306 {
2307 // Load the map of the {rhs}.
2308 Node* rhs_map = assembler->LoadMap(rhs);
2309
2310 // The {rhs} could be a HeapNumber with the same value as {lhs}.
2311 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler);
2312 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
2313 &if_rhsisnumber, &if_rhsisnotnumber);
2314
2315 assembler->Bind(&if_rhsisnumber);
2316 {
2317 // Convert {lhs} and {rhs} to floating point values.
2318 Node* lhs_value = assembler->SmiToFloat64(lhs);
2319 Node* rhs_value = assembler->LoadHeapNumberValue(rhs);
2320
2321 // Perform a floating point comparison of {lhs} and {rhs}.
2322 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal,
2323 &if_notequal);
2324 }
2325
2326 assembler->Bind(&if_rhsisnotnumber);
2327 assembler->Goto(&if_notequal);
2328 }
2329 }
2330 }
2331
2332 assembler->Bind(&if_equal);
2333 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult));
2334
2335 assembler->Bind(&if_notequal);
2336 assembler->Return(assembler->BooleanConstant(mode == kNegateResult));
2337}
2338
2339void GenerateStringRelationalComparison(compiler::CodeStubAssembler* assembler,
2340 RelationalComparisonMode mode) {
2341 typedef compiler::CodeStubAssembler::Label Label;
2342 typedef compiler::Node Node;
2343 typedef compiler::CodeStubAssembler::Variable Variable;
2344
2345 Node* lhs = assembler->Parameter(0);
2346 Node* rhs = assembler->Parameter(1);
2347 Node* context = assembler->Parameter(2);
2348
2349 Label if_less(assembler), if_equal(assembler), if_greater(assembler);
2350
2351 // Fast check to see if {lhs} and {rhs} refer to the same String object.
2352 Label if_same(assembler), if_notsame(assembler);
2353 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
2354
2355 assembler->Bind(&if_same);
2356 assembler->Goto(&if_equal);
2357
2358 assembler->Bind(&if_notsame);
2359 {
2360 // Load instance types of {lhs} and {rhs}.
2361 Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
2362 Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
2363
2364 // Combine the instance types into a single 16-bit value, so we can check
2365 // both of them at once.
2366 Node* both_instance_types = assembler->Word32Or(
2367 lhs_instance_type,
2368 assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
2369
2370 // Check that both {lhs} and {rhs} are flat one-byte strings.
2371 int const kBothSeqOneByteStringMask =
2372 kStringEncodingMask | kStringRepresentationMask |
2373 ((kStringEncodingMask | kStringRepresentationMask) << 8);
2374 int const kBothSeqOneByteStringTag =
2375 kOneByteStringTag | kSeqStringTag |
2376 ((kOneByteStringTag | kSeqStringTag) << 8);
2377 Label if_bothonebyteseqstrings(assembler),
2378 if_notbothonebyteseqstrings(assembler);
2379 assembler->Branch(assembler->Word32Equal(
2380 assembler->Word32And(both_instance_types,
2381 assembler->Int32Constant(
2382 kBothSeqOneByteStringMask)),
2383 assembler->Int32Constant(kBothSeqOneByteStringTag)),
2384 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
2385
2386 assembler->Bind(&if_bothonebyteseqstrings);
2387 {
2388 // Load the length of {lhs} and {rhs}.
2389 Node* lhs_length = assembler->LoadObjectField(lhs, String::kLengthOffset);
2390 Node* rhs_length = assembler->LoadObjectField(rhs, String::kLengthOffset);
2391
2392 // Determine the minimum length.
2393 Node* length = assembler->SmiMin(lhs_length, rhs_length);
2394
2395 // Compute the effective offset of the first character.
2396 Node* begin = assembler->IntPtrConstant(SeqOneByteString::kHeaderSize -
2397 kHeapObjectTag);
2398
2399 // Compute the first offset after the string from the length.
2400 Node* end = assembler->IntPtrAdd(begin, assembler->SmiUntag(length));
2401
2402 // Loop over the {lhs} and {rhs} strings to see if they are equal.
2403 Variable var_offset(assembler, MachineType::PointerRepresentation());
2404 Label loop(assembler, &var_offset);
2405 var_offset.Bind(begin);
2406 assembler->Goto(&loop);
2407 assembler->Bind(&loop);
2408 {
2409 // Check if {offset} equals {end}.
2410 Node* offset = var_offset.value();
2411 Label if_done(assembler), if_notdone(assembler);
2412 assembler->Branch(assembler->WordEqual(offset, end), &if_done,
2413 &if_notdone);
2414
2415 assembler->Bind(&if_notdone);
2416 {
2417 // Load the next characters from {lhs} and {rhs}.
2418 Node* lhs_value = assembler->Load(MachineType::Uint8(), lhs, offset);
2419 Node* rhs_value = assembler->Load(MachineType::Uint8(), rhs, offset);
2420
2421 // Check if the characters match.
2422 Label if_valueissame(assembler), if_valueisnotsame(assembler);
2423 assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
2424 &if_valueissame, &if_valueisnotsame);
2425
2426 assembler->Bind(&if_valueissame);
2427 {
2428 // Advance to next character.
2429 var_offset.Bind(
2430 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
2431 }
2432 assembler->Goto(&loop);
2433
2434 assembler->Bind(&if_valueisnotsame);
2435 assembler->BranchIf(assembler->Uint32LessThan(lhs_value, rhs_value),
2436 &if_less, &if_greater);
2437 }
2438
2439 assembler->Bind(&if_done);
2440 {
2441 // All characters up to the min length are equal, decide based on
2442 // string length.
2443 Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
2444 assembler->Branch(assembler->SmiEqual(lhs_length, rhs_length),
2445 &if_lengthisequal, &if_lengthisnotequal);
2446
2447 assembler->Bind(&if_lengthisequal);
2448 assembler->Goto(&if_equal);
2449
2450 assembler->Bind(&if_lengthisnotequal);
2451 assembler->BranchIfSmiLessThan(lhs_length, rhs_length, &if_less,
2452 &if_greater);
2453 }
2454 }
2455 }
2456
2457 assembler->Bind(&if_notbothonebyteseqstrings);
2458 {
2459 // TODO(bmeurer): Add fast case support for flattened cons strings;
2460 // also add support for two byte string relational comparisons.
2461 switch (mode) {
2462 case kLessThan:
2463 assembler->TailCallRuntime(Runtime::kStringLessThan, context, lhs,
2464 rhs);
2465 break;
2466 case kLessThanOrEqual:
2467 assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual, context,
2468 lhs, rhs);
2469 break;
2470 case kGreaterThan:
2471 assembler->TailCallRuntime(Runtime::kStringGreaterThan, context, lhs,
2472 rhs);
2473 break;
2474 case kGreaterThanOrEqual:
2475 assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual,
2476 context, lhs, rhs);
2477 break;
2478 }
2479 }
2480 }
2481
2482 assembler->Bind(&if_less);
2483 switch (mode) {
2484 case kLessThan:
2485 case kLessThanOrEqual:
2486 assembler->Return(assembler->BooleanConstant(true));
2487 break;
2488
2489 case kGreaterThan:
2490 case kGreaterThanOrEqual:
2491 assembler->Return(assembler->BooleanConstant(false));
2492 break;
2493 }
2494
2495 assembler->Bind(&if_equal);
2496 switch (mode) {
2497 case kLessThan:
2498 case kGreaterThan:
2499 assembler->Return(assembler->BooleanConstant(false));
2500 break;
2501
2502 case kLessThanOrEqual:
2503 case kGreaterThanOrEqual:
2504 assembler->Return(assembler->BooleanConstant(true));
2505 break;
2506 }
2507
2508 assembler->Bind(&if_greater);
2509 switch (mode) {
2510 case kLessThan:
2511 case kLessThanOrEqual:
2512 assembler->Return(assembler->BooleanConstant(false));
2513 break;
2514
2515 case kGreaterThan:
2516 case kGreaterThanOrEqual:
2517 assembler->Return(assembler->BooleanConstant(true));
2518 break;
2519 }
2520}
2521
2522void GenerateStringEqual(compiler::CodeStubAssembler* assembler,
2523 ResultMode mode) {
2524 // Here's pseudo-code for the algorithm below in case of kDontNegateResult
2525 // mode; for kNegateResult mode we properly negate the result.
2526 //
2527 // if (lhs == rhs) return true;
2528 // if (lhs->length() != rhs->length()) return false;
2529 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) {
2530 // return false;
2531 // }
2532 // if (lhs->IsSeqOneByteString() && rhs->IsSeqOneByteString()) {
2533 // for (i = 0; i != lhs->length(); ++i) {
2534 // if (lhs[i] != rhs[i]) return false;
2535 // }
2536 // return true;
2537 // }
2538 // return %StringEqual(lhs, rhs);
2539
2540 typedef compiler::CodeStubAssembler::Label Label;
2541 typedef compiler::Node Node;
2542 typedef compiler::CodeStubAssembler::Variable Variable;
2543
2544 Node* lhs = assembler->Parameter(0);
2545 Node* rhs = assembler->Parameter(1);
2546 Node* context = assembler->Parameter(2);
2547
2548 Label if_equal(assembler), if_notequal(assembler);
2549
2550 // Fast check to see if {lhs} and {rhs} refer to the same String object.
2551 Label if_same(assembler), if_notsame(assembler);
2552 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
2553
2554 assembler->Bind(&if_same);
2555 assembler->Goto(&if_equal);
2556
2557 assembler->Bind(&if_notsame);
2558 {
2559 // The {lhs} and {rhs} don't refer to the exact same String object.
2560
2561 // Load the length of {lhs} and {rhs}.
2562 Node* lhs_length = assembler->LoadObjectField(lhs, String::kLengthOffset);
2563 Node* rhs_length = assembler->LoadObjectField(rhs, String::kLengthOffset);
2564
2565 // Check if the lengths of {lhs} and {rhs} are equal.
2566 Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
2567 assembler->Branch(assembler->WordEqual(lhs_length, rhs_length),
2568 &if_lengthisequal, &if_lengthisnotequal);
2569
2570 assembler->Bind(&if_lengthisequal);
2571 {
2572 // Load instance types of {lhs} and {rhs}.
2573 Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
2574 Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
2575
2576 // Combine the instance types into a single 16-bit value, so we can check
2577 // both of them at once.
2578 Node* both_instance_types = assembler->Word32Or(
2579 lhs_instance_type,
2580 assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
2581
2582 // Check if both {lhs} and {rhs} are internalized.
2583 int const kBothInternalizedMask =
2584 kIsNotInternalizedMask | (kIsNotInternalizedMask << 8);
2585 int const kBothInternalizedTag =
2586 kInternalizedTag | (kInternalizedTag << 8);
2587 Label if_bothinternalized(assembler), if_notbothinternalized(assembler);
2588 assembler->Branch(assembler->Word32Equal(
2589 assembler->Word32And(both_instance_types,
2590 assembler->Int32Constant(
2591 kBothInternalizedMask)),
2592 assembler->Int32Constant(kBothInternalizedTag)),
2593 &if_bothinternalized, &if_notbothinternalized);
2594
2595 assembler->Bind(&if_bothinternalized);
2596 {
2597 // Fast negative check for internalized-to-internalized equality.
2598 assembler->Goto(&if_notequal);
2599 }
2600
2601 assembler->Bind(&if_notbothinternalized);
2602 {
2603 // Check that both {lhs} and {rhs} are flat one-byte strings.
2604 int const kBothSeqOneByteStringMask =
2605 kStringEncodingMask | kStringRepresentationMask |
2606 ((kStringEncodingMask | kStringRepresentationMask) << 8);
2607 int const kBothSeqOneByteStringTag =
2608 kOneByteStringTag | kSeqStringTag |
2609 ((kOneByteStringTag | kSeqStringTag) << 8);
2610 Label if_bothonebyteseqstrings(assembler),
2611 if_notbothonebyteseqstrings(assembler);
2612 assembler->Branch(
2613 assembler->Word32Equal(
2614 assembler->Word32And(
2615 both_instance_types,
2616 assembler->Int32Constant(kBothSeqOneByteStringMask)),
2617 assembler->Int32Constant(kBothSeqOneByteStringTag)),
2618 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
2619
2620 assembler->Bind(&if_bothonebyteseqstrings);
2621 {
2622 // Compute the effective offset of the first character.
2623 Node* begin = assembler->IntPtrConstant(
2624 SeqOneByteString::kHeaderSize - kHeapObjectTag);
2625
2626 // Compute the first offset after the string from the length.
2627 Node* end =
2628 assembler->IntPtrAdd(begin, assembler->SmiUntag(lhs_length));
2629
2630 // Loop over the {lhs} and {rhs} strings to see if they are equal.
2631 Variable var_offset(assembler, MachineType::PointerRepresentation());
2632 Label loop(assembler, &var_offset);
2633 var_offset.Bind(begin);
2634 assembler->Goto(&loop);
2635 assembler->Bind(&loop);
2636 {
2637 // Check if {offset} equals {end}.
2638 Node* offset = var_offset.value();
2639 Label if_done(assembler), if_notdone(assembler);
2640 assembler->Branch(assembler->WordEqual(offset, end), &if_done,
2641 &if_notdone);
2642
2643 assembler->Bind(&if_notdone);
2644 {
2645 // Load the next characters from {lhs} and {rhs}.
2646 Node* lhs_value =
2647 assembler->Load(MachineType::Uint8(), lhs, offset);
2648 Node* rhs_value =
2649 assembler->Load(MachineType::Uint8(), rhs, offset);
2650
2651 // Check if the characters match.
2652 Label if_valueissame(assembler), if_valueisnotsame(assembler);
2653 assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
2654 &if_valueissame, &if_valueisnotsame);
2655
2656 assembler->Bind(&if_valueissame);
2657 {
2658 // Advance to next character.
2659 var_offset.Bind(
2660 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
2661 }
2662 assembler->Goto(&loop);
2663
2664 assembler->Bind(&if_valueisnotsame);
2665 assembler->Goto(&if_notequal);
2666 }
2667
2668 assembler->Bind(&if_done);
2669 assembler->Goto(&if_equal);
2670 }
2671 }
2672
2673 assembler->Bind(&if_notbothonebyteseqstrings);
2674 {
2675 // TODO(bmeurer): Add fast case support for flattened cons strings;
2676 // also add support for two byte string equality checks.
2677 Runtime::FunctionId function_id = (mode == kDontNegateResult)
2678 ? Runtime::kStringEqual
2679 : Runtime::kStringNotEqual;
2680 assembler->TailCallRuntime(function_id, context, lhs, rhs);
2681 }
2682 }
2683 }
2684
2685 assembler->Bind(&if_lengthisnotequal);
2686 {
2687 // Mismatch in length of {lhs} and {rhs}, cannot be equal.
2688 assembler->Goto(&if_notequal);
2689 }
2690 }
2691
2692 assembler->Bind(&if_equal);
2693 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult));
2694
2695 assembler->Bind(&if_notequal);
2696 assembler->Return(assembler->BooleanConstant(mode == kNegateResult));
2697}
2698
2699} // namespace
2700
2701void LessThanStub::GenerateAssembly(
2702 compiler::CodeStubAssembler* assembler) const {
2703 GenerateAbstractRelationalComparison(assembler, kLessThan);
2704}
2705
2706void LessThanOrEqualStub::GenerateAssembly(
2707 compiler::CodeStubAssembler* assembler) const {
2708 GenerateAbstractRelationalComparison(assembler, kLessThanOrEqual);
2709}
2710
2711void GreaterThanStub::GenerateAssembly(
2712 compiler::CodeStubAssembler* assembler) const {
2713 GenerateAbstractRelationalComparison(assembler, kGreaterThan);
2714}
2715
2716void GreaterThanOrEqualStub::GenerateAssembly(
2717 compiler::CodeStubAssembler* assembler) const {
2718 GenerateAbstractRelationalComparison(assembler, kGreaterThanOrEqual);
2719}
2720
2721void EqualStub::GenerateAssembly(compiler::CodeStubAssembler* assembler) const {
2722 GenerateEqual(assembler, kDontNegateResult);
2723}
2724
2725void NotEqualStub::GenerateAssembly(
2726 compiler::CodeStubAssembler* assembler) const {
2727 GenerateEqual(assembler, kNegateResult);
2728}
2729
2730void StrictEqualStub::GenerateAssembly(
2731 compiler::CodeStubAssembler* assembler) const {
2732 GenerateStrictEqual(assembler, kDontNegateResult);
2733}
2734
2735void StrictNotEqualStub::GenerateAssembly(
2736 compiler::CodeStubAssembler* assembler) const {
2737 GenerateStrictEqual(assembler, kNegateResult);
2738}
2739
2740void StringEqualStub::GenerateAssembly(
2741 compiler::CodeStubAssembler* assembler) const {
2742 GenerateStringEqual(assembler, kDontNegateResult);
2743}
2744
2745void StringNotEqualStub::GenerateAssembly(
2746 compiler::CodeStubAssembler* assembler) const {
2747 GenerateStringEqual(assembler, kNegateResult);
2748}
2749
2750void StringLessThanStub::GenerateAssembly(
2751 compiler::CodeStubAssembler* assembler) const {
2752 GenerateStringRelationalComparison(assembler, kLessThan);
2753}
2754
2755void StringLessThanOrEqualStub::GenerateAssembly(
2756 compiler::CodeStubAssembler* assembler) const {
2757 GenerateStringRelationalComparison(assembler, kLessThanOrEqual);
2758}
2759
2760void StringGreaterThanStub::GenerateAssembly(
2761 compiler::CodeStubAssembler* assembler) const {
2762 GenerateStringRelationalComparison(assembler, kGreaterThan);
2763}
2764
2765void StringGreaterThanOrEqualStub::GenerateAssembly(
2766 compiler::CodeStubAssembler* assembler) const {
2767 GenerateStringRelationalComparison(assembler, kGreaterThanOrEqual);
2768}
2769
2770void ToLengthStub::GenerateAssembly(
2771 compiler::CodeStubAssembler* assembler) const {
2772 typedef compiler::CodeStubAssembler::Label Label;
2773 typedef compiler::Node Node;
2774 typedef compiler::CodeStubAssembler::Variable Variable;
2775
2776 Node* context = assembler->Parameter(1);
2777
2778 // We might need to loop once for ToNumber conversion.
2779 Variable var_len(assembler, MachineRepresentation::kTagged);
2780 Label loop(assembler, &var_len);
2781 var_len.Bind(assembler->Parameter(0));
2782 assembler->Goto(&loop);
2783 assembler->Bind(&loop);
2784 {
2785 // Shared entry points.
2786 Label return_len(assembler),
2787 return_two53minus1(assembler, Label::kDeferred),
2788 return_zero(assembler, Label::kDeferred);
2789
2790 // Load the current {len} value.
2791 Node* len = var_len.value();
2792
2793 // Check if {len} is a positive Smi.
2794 assembler->GotoIf(assembler->WordIsPositiveSmi(len), &return_len);
2795
2796 // Check if {len} is a (negative) Smi.
2797 assembler->GotoIf(assembler->WordIsSmi(len), &return_zero);
2798
2799 // Check if {len} is a HeapNumber.
2800 Label if_lenisheapnumber(assembler),
2801 if_lenisnotheapnumber(assembler, Label::kDeferred);
2802 assembler->Branch(assembler->WordEqual(assembler->LoadMap(len),
2803 assembler->HeapNumberMapConstant()),
2804 &if_lenisheapnumber, &if_lenisnotheapnumber);
2805
2806 assembler->Bind(&if_lenisheapnumber);
2807 {
2808 // Load the floating-point value of {len}.
2809 Node* len_value = assembler->LoadHeapNumberValue(len);
2810
2811 // Check if {len} is not greater than zero.
2812 assembler->GotoUnless(assembler->Float64GreaterThan(
2813 len_value, assembler->Float64Constant(0.0)),
2814 &return_zero);
2815
2816 // Check if {len} is greater than or equal to 2^53-1.
2817 assembler->GotoIf(
2818 assembler->Float64GreaterThanOrEqual(
2819 len_value, assembler->Float64Constant(kMaxSafeInteger)),
2820 &return_two53minus1);
2821
2822 // Round the {len} towards -Infinity.
2823 Node* value = assembler->Float64Floor(len_value);
2824 Node* result = assembler->ChangeFloat64ToTagged(value);
2825 assembler->Return(result);
2826 }
2827
2828 assembler->Bind(&if_lenisnotheapnumber);
2829 {
2830 // Need to convert {len} to a Number first.
2831 Callable callable = CodeFactory::NonNumberToNumber(assembler->isolate());
2832 var_len.Bind(assembler->CallStub(callable, context, len));
2833 assembler->Goto(&loop);
2834 }
2835
2836 assembler->Bind(&return_len);
2837 assembler->Return(var_len.value());
2838
2839 assembler->Bind(&return_two53minus1);
2840 assembler->Return(assembler->NumberConstant(kMaxSafeInteger));
2841
2842 assembler->Bind(&return_zero);
2843 assembler->Return(assembler->SmiConstant(Smi::FromInt(0)));
2844 }
2845}
2846
2847void ToBooleanStub::GenerateAssembly(
2848 compiler::CodeStubAssembler* assembler) const {
2849 typedef compiler::Node Node;
2850 typedef compiler::CodeStubAssembler::Label Label;
2851
2852 Node* value = assembler->Parameter(0);
2853 Label if_valueissmi(assembler), if_valueisnotsmi(assembler);
2854
2855 // Check if {value} is a Smi or a HeapObject.
2856 assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi,
2857 &if_valueisnotsmi);
2858
2859 assembler->Bind(&if_valueissmi);
2860 {
2861 // The {value} is a Smi, only need to check against zero.
2862 Label if_valueiszero(assembler), if_valueisnotzero(assembler);
2863 assembler->Branch(assembler->SmiEqual(value, assembler->SmiConstant(0)),
2864 &if_valueiszero, &if_valueisnotzero);
2865
2866 assembler->Bind(&if_valueiszero);
2867 assembler->Return(assembler->BooleanConstant(false));
2868
2869 assembler->Bind(&if_valueisnotzero);
2870 assembler->Return(assembler->BooleanConstant(true));
2871 }
2872
2873 assembler->Bind(&if_valueisnotsmi);
2874 {
2875 Label if_valueisstring(assembler), if_valueisheapnumber(assembler),
2876 if_valueisoddball(assembler), if_valueisother(assembler);
2877
2878 // The {value} is a HeapObject, load its map.
2879 Node* value_map = assembler->LoadMap(value);
2880
2881 // Load the {value}s instance type.
2882 Node* value_instance_type = assembler->Load(
2883 MachineType::Uint8(), value_map,
2884 assembler->IntPtrConstant(Map::kInstanceTypeOffset - kHeapObjectTag));
2885
2886 // Dispatch based on the instance type; we distinguish all String instance
2887 // types, the HeapNumber type and the Oddball type.
2888 size_t const kNumCases = FIRST_NONSTRING_TYPE + 2;
2889 Label* case_labels[kNumCases];
2890 int32_t case_values[kNumCases];
2891 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) {
2892 case_labels[i] = new Label(assembler);
2893 case_values[i] = i;
2894 }
2895 case_labels[FIRST_NONSTRING_TYPE + 0] = &if_valueisheapnumber;
2896 case_values[FIRST_NONSTRING_TYPE + 0] = HEAP_NUMBER_TYPE;
2897 case_labels[FIRST_NONSTRING_TYPE + 1] = &if_valueisoddball;
2898 case_values[FIRST_NONSTRING_TYPE + 1] = ODDBALL_TYPE;
2899 assembler->Switch(value_instance_type, &if_valueisother, case_values,
2900 case_labels, arraysize(case_values));
2901 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) {
2902 assembler->Bind(case_labels[i]);
2903 assembler->Goto(&if_valueisstring);
2904 delete case_labels[i];
2905 }
2906
2907 assembler->Bind(&if_valueisstring);
2908 {
2909 // Load the string length field of the {value}.
2910 Node* value_length =
2911 assembler->LoadObjectField(value, String::kLengthOffset);
2912
2913 // Check if the {value} is the empty string.
2914 Label if_valueisempty(assembler), if_valueisnotempty(assembler);
2915 assembler->Branch(
2916 assembler->SmiEqual(value_length, assembler->SmiConstant(0)),
2917 &if_valueisempty, &if_valueisnotempty);
2918
2919 assembler->Bind(&if_valueisempty);
2920 assembler->Return(assembler->BooleanConstant(false));
2921
2922 assembler->Bind(&if_valueisnotempty);
2923 assembler->Return(assembler->BooleanConstant(true));
2924 }
2925
2926 assembler->Bind(&if_valueisheapnumber);
2927 {
2928 Node* value_value = assembler->Load(
2929 MachineType::Float64(), value,
2930 assembler->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag));
2931
2932 Label if_valueispositive(assembler), if_valueisnotpositive(assembler),
2933 if_valueisnegative(assembler), if_valueisnanorzero(assembler);
2934 assembler->Branch(assembler->Float64LessThan(
2935 assembler->Float64Constant(0.0), value_value),
2936 &if_valueispositive, &if_valueisnotpositive);
2937
2938 assembler->Bind(&if_valueispositive);
2939 assembler->Return(assembler->BooleanConstant(true));
2940
2941 assembler->Bind(&if_valueisnotpositive);
2942 assembler->Branch(assembler->Float64LessThan(
2943 value_value, assembler->Float64Constant(0.0)),
2944 &if_valueisnegative, &if_valueisnanorzero);
2945
2946 assembler->Bind(&if_valueisnegative);
2947 assembler->Return(assembler->BooleanConstant(true));
2948
2949 assembler->Bind(&if_valueisnanorzero);
2950 assembler->Return(assembler->BooleanConstant(false));
2951 }
2952
2953 assembler->Bind(&if_valueisoddball);
2954 {
2955 // The {value} is an Oddball, and every Oddball knows its boolean value.
2956 Node* value_toboolean =
2957 assembler->LoadObjectField(value, Oddball::kToBooleanOffset);
2958 assembler->Return(value_toboolean);
2959 }
2960
2961 assembler->Bind(&if_valueisother);
2962 {
2963 Node* value_map_bitfield = assembler->Load(
2964 MachineType::Uint8(), value_map,
2965 assembler->IntPtrConstant(Map::kBitFieldOffset - kHeapObjectTag));
2966 Node* value_map_undetectable = assembler->Word32And(
2967 value_map_bitfield,
2968 assembler->Int32Constant(1 << Map::kIsUndetectable));
2969
2970 // Check if the {value} is undetectable.
2971 Label if_valueisundetectable(assembler),
2972 if_valueisnotundetectable(assembler);
2973 assembler->Branch(assembler->Word32Equal(value_map_undetectable,
2974 assembler->Int32Constant(0)),
2975 &if_valueisnotundetectable, &if_valueisundetectable);
2976
2977 assembler->Bind(&if_valueisundetectable);
2978 assembler->Return(assembler->BooleanConstant(false));
2979
2980 assembler->Bind(&if_valueisnotundetectable);
2981 assembler->Return(assembler->BooleanConstant(true));
2982 }
2983 }
2984}
2985
2986void ToIntegerStub::GenerateAssembly(
2987 compiler::CodeStubAssembler* assembler) const {
2988 typedef compiler::CodeStubAssembler::Label Label;
2989 typedef compiler::Node Node;
2990 typedef compiler::CodeStubAssembler::Variable Variable;
2991
2992 Node* context = assembler->Parameter(1);
2993
2994 // We might need to loop once for ToNumber conversion.
2995 Variable var_arg(assembler, MachineRepresentation::kTagged);
2996 Label loop(assembler, &var_arg);
2997 var_arg.Bind(assembler->Parameter(0));
2998 assembler->Goto(&loop);
2999 assembler->Bind(&loop);
3000 {
3001 // Shared entry points.
3002 Label return_arg(assembler), return_zero(assembler, Label::kDeferred);
3003
3004 // Load the current {arg} value.
3005 Node* arg = var_arg.value();
3006
3007 // Check if {arg} is a Smi.
3008 assembler->GotoIf(assembler->WordIsSmi(arg), &return_arg);
3009
3010 // Check if {arg} is a HeapNumber.
3011 Label if_argisheapnumber(assembler),
3012 if_argisnotheapnumber(assembler, Label::kDeferred);
3013 assembler->Branch(assembler->WordEqual(assembler->LoadMap(arg),
3014 assembler->HeapNumberMapConstant()),
3015 &if_argisheapnumber, &if_argisnotheapnumber);
3016
3017 assembler->Bind(&if_argisheapnumber);
3018 {
3019 // Load the floating-point value of {arg}.
3020 Node* arg_value = assembler->LoadHeapNumberValue(arg);
3021
3022 // Check if {arg} is NaN.
3023 assembler->GotoUnless(assembler->Float64Equal(arg_value, arg_value),
3024 &return_zero);
3025
3026 // Truncate {arg} towards zero.
3027 Node* value = assembler->Float64Trunc(arg_value);
3028 var_arg.Bind(assembler->ChangeFloat64ToTagged(value));
3029 assembler->Goto(&return_arg);
3030 }
3031
3032 assembler->Bind(&if_argisnotheapnumber);
3033 {
3034 // Need to convert {arg} to a Number first.
3035 Callable callable = CodeFactory::NonNumberToNumber(assembler->isolate());
3036 var_arg.Bind(assembler->CallStub(callable, context, arg));
3037 assembler->Goto(&loop);
3038 }
3039
3040 assembler->Bind(&return_arg);
3041 assembler->Return(var_arg.value());
3042
3043 assembler->Bind(&return_zero);
3044 assembler->Return(assembler->SmiConstant(Smi::FromInt(0)));
3045 }
3046}
3047
3048void StoreInterceptorStub::GenerateAssembly(
3049 compiler::CodeStubAssembler* assembler) const {
3050 typedef compiler::Node Node;
3051 Node* receiver = assembler->Parameter(0);
3052 Node* name = assembler->Parameter(1);
3053 Node* value = assembler->Parameter(2);
3054 Node* context = assembler->Parameter(3);
3055 assembler->TailCallRuntime(Runtime::kStorePropertyWithInterceptor, context,
3056 receiver, name, value);
3057}
3058
3059void LoadIndexedInterceptorStub::GenerateAssembly(
3060 compiler::CodeStubAssembler* assembler) const {
3061 typedef compiler::Node Node;
3062 typedef compiler::CodeStubAssembler::Label Label;
3063 Node* receiver = assembler->Parameter(0);
3064 Node* key = assembler->Parameter(1);
3065 Node* slot = assembler->Parameter(2);
3066 Node* vector = assembler->Parameter(3);
3067 Node* context = assembler->Parameter(4);
3068
3069 Label if_keyispositivesmi(assembler), if_keyisinvalid(assembler);
3070 assembler->Branch(assembler->WordIsPositiveSmi(key), &if_keyispositivesmi,
3071 &if_keyisinvalid);
3072 assembler->Bind(&if_keyispositivesmi);
3073 assembler->TailCallRuntime(Runtime::kLoadElementWithInterceptor, context,
3074 receiver, key);
3075
3076 assembler->Bind(&if_keyisinvalid);
3077 assembler->TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key,
3078 slot, vector);
3079}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003080
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003081template<class StateType>
3082void HydrogenCodeStub::TraceTransition(StateType from, StateType to) {
3083 // Note: Although a no-op transition is semantically OK, it is hinting at a
3084 // bug somewhere in our state transition machinery.
3085 DCHECK(from != to);
3086 if (!FLAG_trace_ic) return;
3087 OFStream os(stdout);
3088 os << "[";
3089 PrintBaseName(os);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003090 os << ": " << from << "=>" << to << "]" << std::endl;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003091}
3092
3093
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003094// TODO(svenpanne) Make this a real infix_ostream_iterator.
3095class SimpleListPrinter {
3096 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003097 explicit SimpleListPrinter(std::ostream& os) : os_(os), first_(true) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003098
3099 void Add(const char* s) {
3100 if (first_) {
3101 first_ = false;
3102 } else {
3103 os_ << ",";
3104 }
3105 os_ << s;
Ben Murdoch086aeea2011-05-13 15:57:08 +01003106 }
3107
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003108 private:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003109 std::ostream& os_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003110 bool first_;
3111};
3112
3113
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003114void CallICStub::PrintState(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003115 os << state();
3116}
3117
3118
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003119void JSEntryStub::FinishCode(Handle<Code> code) {
3120 Handle<FixedArray> handler_table =
3121 code->GetIsolate()->factory()->NewFixedArray(1, TENURED);
3122 handler_table->set(0, Smi::FromInt(handler_offset_));
3123 code->set_handler_table(*handler_table);
3124}
3125
3126
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003127void LoadDictionaryElementStub::InitializeDescriptor(
3128 CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003129 descriptor->Initialize(
3130 FUNCTION_ADDR(Runtime_KeyedLoadIC_MissFromStubFailure));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003131}
3132
3133
3134void KeyedLoadGenericStub::InitializeDescriptor(
3135 CodeStubDescriptor* descriptor) {
3136 descriptor->Initialize(
Ben Murdoch097c5b22016-05-18 11:27:45 +01003137 Runtime::FunctionForId(Runtime::kKeyedGetProperty)->entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003138}
3139
3140
3141void HandlerStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
3142 if (kind() == Code::STORE_IC) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003143 descriptor->Initialize(FUNCTION_ADDR(Runtime_StoreIC_MissFromStubFailure));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003144 } else if (kind() == Code::KEYED_LOAD_IC) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003145 descriptor->Initialize(
3146 FUNCTION_ADDR(Runtime_KeyedLoadIC_MissFromStubFailure));
3147 } else if (kind() == Code::KEYED_STORE_IC) {
3148 descriptor->Initialize(
3149 FUNCTION_ADDR(Runtime_KeyedStoreIC_MissFromStubFailure));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003150 }
3151}
3152
3153
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003154CallInterfaceDescriptor HandlerStub::GetCallInterfaceDescriptor() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003155 if (kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003156 return LoadWithVectorDescriptor(isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003157 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003158 DCHECK(kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC);
3159 return VectorStoreICDescriptor(isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003160 }
3161}
3162
3163
3164void StoreFastElementStub::InitializeDescriptor(
3165 CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003166 descriptor->Initialize(
3167 FUNCTION_ADDR(Runtime_KeyedStoreIC_MissFromStubFailure));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003168}
3169
3170
3171void ElementsTransitionAndStoreStub::InitializeDescriptor(
3172 CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003173 descriptor->Initialize(
3174 FUNCTION_ADDR(Runtime_ElementsTransitionAndStoreIC_Miss));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003175}
3176
3177
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003178void ToObjectStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
3179 descriptor->Initialize(Runtime::FunctionForId(Runtime::kToObject)->entry);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003180}
3181
3182
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003183CallInterfaceDescriptor StoreTransitionStub::GetCallInterfaceDescriptor()
3184 const {
3185 return VectorStoreTransitionDescriptor(isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003186}
3187
3188
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003189CallInterfaceDescriptor
3190ElementsTransitionAndStoreStub::GetCallInterfaceDescriptor() const {
3191 return VectorStoreTransitionDescriptor(isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003192}
3193
3194
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003195void FastNewClosureStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003196 descriptor->Initialize(Runtime::FunctionForId(Runtime::kNewClosure)->entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003197}
3198
3199
3200void FastNewContextStub::InitializeDescriptor(CodeStubDescriptor* d) {}
3201
3202
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003203void TypeofStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {}
3204
3205
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003206void NumberToStringStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003207 descriptor->Initialize(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003208 Runtime::FunctionForId(Runtime::kNumberToString)->entry);
3209}
3210
3211
3212void FastCloneRegExpStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
3213 FastCloneRegExpDescriptor call_descriptor(isolate());
3214 descriptor->Initialize(
3215 Runtime::FunctionForId(Runtime::kCreateRegExpLiteral)->entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003216}
3217
3218
3219void FastCloneShallowArrayStub::InitializeDescriptor(
3220 CodeStubDescriptor* descriptor) {
3221 FastCloneShallowArrayDescriptor call_descriptor(isolate());
3222 descriptor->Initialize(
3223 Runtime::FunctionForId(Runtime::kCreateArrayLiteralStubBailout)->entry);
3224}
3225
3226
3227void FastCloneShallowObjectStub::InitializeDescriptor(
3228 CodeStubDescriptor* descriptor) {
3229 FastCloneShallowObjectDescriptor call_descriptor(isolate());
3230 descriptor->Initialize(
3231 Runtime::FunctionForId(Runtime::kCreateObjectLiteral)->entry);
3232}
3233
3234
3235void CreateAllocationSiteStub::InitializeDescriptor(CodeStubDescriptor* d) {}
3236
3237
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003238void CreateWeakCellStub::InitializeDescriptor(CodeStubDescriptor* d) {}
3239
3240
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003241void RegExpConstructResultStub::InitializeDescriptor(
3242 CodeStubDescriptor* descriptor) {
3243 descriptor->Initialize(
3244 Runtime::FunctionForId(Runtime::kRegExpConstructResult)->entry);
3245}
3246
3247
3248void TransitionElementsKindStub::InitializeDescriptor(
3249 CodeStubDescriptor* descriptor) {
3250 descriptor->Initialize(
3251 Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry);
3252}
3253
3254
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003255void AllocateHeapNumberStub::InitializeDescriptor(
3256 CodeStubDescriptor* descriptor) {
3257 descriptor->Initialize(
3258 Runtime::FunctionForId(Runtime::kAllocateHeapNumber)->entry);
3259}
3260
3261
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003262void AllocateMutableHeapNumberStub::InitializeDescriptor(
3263 CodeStubDescriptor* descriptor) {
3264 descriptor->Initialize();
3265}
3266
Ben Murdochda12d292016-06-02 14:46:10 +01003267#define SIMD128_INIT_DESC(TYPE, Type, type, lane_count, lane_type) \
3268 void Allocate##Type##Stub::InitializeDescriptor( \
3269 CodeStubDescriptor* descriptor) { \
3270 descriptor->Initialize( \
3271 Runtime::FunctionForId(Runtime::kCreate##Type)->entry); \
3272 }
3273SIMD128_TYPES(SIMD128_INIT_DESC)
3274#undef SIMD128_INIT_DESC
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003275
3276void AllocateInNewSpaceStub::InitializeDescriptor(
3277 CodeStubDescriptor* descriptor) {
3278 descriptor->Initialize();
3279}
3280
Ben Murdochda12d292016-06-02 14:46:10 +01003281void ToBooleanICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003282 descriptor->Initialize(FUNCTION_ADDR(Runtime_ToBooleanIC_Miss));
3283 descriptor->SetMissHandler(ExternalReference(
3284 Runtime::FunctionForId(Runtime::kToBooleanIC_Miss), isolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003285}
3286
3287
3288void BinaryOpICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003289 descriptor->Initialize(FUNCTION_ADDR(Runtime_BinaryOpIC_Miss));
3290 descriptor->SetMissHandler(ExternalReference(
3291 Runtime::FunctionForId(Runtime::kBinaryOpIC_Miss), isolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003292}
3293
3294
3295void BinaryOpWithAllocationSiteStub::InitializeDescriptor(
3296 CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003297 descriptor->Initialize(
3298 FUNCTION_ADDR(Runtime_BinaryOpIC_MissWithAllocationSite));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003299}
3300
3301
3302void StringAddStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
3303 descriptor->Initialize(Runtime::FunctionForId(Runtime::kStringAdd)->entry);
3304}
3305
3306
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003307void GrowArrayElementsStub::InitializeDescriptor(
3308 CodeStubDescriptor* descriptor) {
3309 descriptor->Initialize(
3310 Runtime::FunctionForId(Runtime::kGrowArrayElements)->entry);
3311}
3312
3313
3314void TypeofStub::GenerateAheadOfTime(Isolate* isolate) {
3315 TypeofStub stub(isolate);
3316 stub.GetCode();
3317}
3318
3319
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003320void CreateAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
3321 CreateAllocationSiteStub stub(isolate);
3322 stub.GetCode();
3323}
3324
3325
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003326void CreateWeakCellStub::GenerateAheadOfTime(Isolate* isolate) {
3327 CreateWeakCellStub stub(isolate);
3328 stub.GetCode();
3329}
3330
3331
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003332void StoreElementStub::Generate(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01003333 DCHECK_EQ(DICTIONARY_ELEMENTS, elements_kind());
3334 ElementHandlerCompiler::GenerateStoreSlow(masm);
Ben Murdoch257744e2011-11-30 15:57:28 +00003335}
3336
3337
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003338// static
3339void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) {
3340 StoreFastElementStub(isolate, false, FAST_HOLEY_ELEMENTS, STANDARD_STORE)
3341 .GetCode();
3342 StoreFastElementStub(isolate, false, FAST_HOLEY_ELEMENTS,
3343 STORE_AND_GROW_NO_TRANSITION).GetCode();
3344 for (int i = FIRST_FAST_ELEMENTS_KIND; i <= LAST_FAST_ELEMENTS_KIND; i++) {
3345 ElementsKind kind = static_cast<ElementsKind>(i);
3346 StoreFastElementStub(isolate, true, kind, STANDARD_STORE).GetCode();
3347 StoreFastElementStub(isolate, true, kind, STORE_AND_GROW_NO_TRANSITION)
3348 .GetCode();
3349 }
3350}
3351
3352
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003353void ArrayConstructorStub::PrintName(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003354 os << "ArrayConstructorStub";
3355 switch (argument_count()) {
3356 case ANY:
3357 os << "_Any";
3358 break;
3359 case NONE:
3360 os << "_None";
3361 break;
3362 case ONE:
3363 os << "_One";
3364 break;
3365 case MORE_THAN_ONE:
3366 os << "_More_Than_One";
3367 break;
3368 }
3369 return;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003370}
3371
3372
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003373std::ostream& ArrayConstructorStubBase::BasePrintName(
3374 std::ostream& os, // NOLINT
3375 const char* name) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003376 os << name << "_" << ElementsKindToString(elements_kind());
3377 if (override_mode() == DISABLE_ALLOCATION_SITES) {
3378 os << "_DISABLE_ALLOCATION_SITES";
3379 }
3380 return os;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003381}
3382
Ben Murdochda12d292016-06-02 14:46:10 +01003383bool ToBooleanICStub::UpdateStatus(Handle<Object> object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003384 Types new_types = types();
3385 Types old_types = new_types;
3386 bool to_boolean_value = new_types.UpdateStatus(object);
3387 TraceTransition(old_types, new_types);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003388 set_sub_minor_key(TypesBits::update(sub_minor_key(), new_types.ToIntegral()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003389 return to_boolean_value;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003390}
3391
Ben Murdochda12d292016-06-02 14:46:10 +01003392void ToBooleanICStub::PrintState(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003393 os << types();
3394}
3395
Ben Murdochda12d292016-06-02 14:46:10 +01003396std::ostream& operator<<(std::ostream& os, const ToBooleanICStub::Types& s) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003397 os << "(";
3398 SimpleListPrinter p(os);
3399 if (s.IsEmpty()) p.Add("None");
Ben Murdochda12d292016-06-02 14:46:10 +01003400 if (s.Contains(ToBooleanICStub::UNDEFINED)) p.Add("Undefined");
3401 if (s.Contains(ToBooleanICStub::BOOLEAN)) p.Add("Bool");
3402 if (s.Contains(ToBooleanICStub::NULL_TYPE)) p.Add("Null");
3403 if (s.Contains(ToBooleanICStub::SMI)) p.Add("Smi");
3404 if (s.Contains(ToBooleanICStub::SPEC_OBJECT)) p.Add("SpecObject");
3405 if (s.Contains(ToBooleanICStub::STRING)) p.Add("String");
3406 if (s.Contains(ToBooleanICStub::SYMBOL)) p.Add("Symbol");
3407 if (s.Contains(ToBooleanICStub::HEAP_NUMBER)) p.Add("HeapNumber");
3408 if (s.Contains(ToBooleanICStub::SIMD_VALUE)) p.Add("SimdValue");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003409 return os << ")";
3410}
3411
Ben Murdochda12d292016-06-02 14:46:10 +01003412bool ToBooleanICStub::Types::UpdateStatus(Handle<Object> object) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003413 if (object->IsUndefined()) {
3414 Add(UNDEFINED);
3415 return false;
3416 } else if (object->IsBoolean()) {
3417 Add(BOOLEAN);
3418 return object->IsTrue();
3419 } else if (object->IsNull()) {
3420 Add(NULL_TYPE);
3421 return false;
3422 } else if (object->IsSmi()) {
3423 Add(SMI);
3424 return Smi::cast(*object)->value() != 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003425 } else if (object->IsJSReceiver()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003426 Add(SPEC_OBJECT);
Ben Murdochda12d292016-06-02 14:46:10 +01003427 return !object->IsUndetectable();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003428 } else if (object->IsString()) {
Ben Murdochda12d292016-06-02 14:46:10 +01003429 DCHECK(!object->IsUndetectable());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003430 Add(STRING);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003431 return String::cast(*object)->length() != 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003432 } else if (object->IsSymbol()) {
3433 Add(SYMBOL);
3434 return true;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003435 } else if (object->IsHeapNumber()) {
Ben Murdochda12d292016-06-02 14:46:10 +01003436 DCHECK(!object->IsUndetectable());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003437 Add(HEAP_NUMBER);
3438 double value = HeapNumber::cast(*object)->value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003439 return value != 0 && !std::isnan(value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003440 } else if (object->IsSimd128Value()) {
3441 Add(SIMD_VALUE);
3442 return true;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003443 } else {
3444 // We should never see an internal object at runtime here!
3445 UNREACHABLE();
3446 return true;
3447 }
3448}
3449
Ben Murdochda12d292016-06-02 14:46:10 +01003450bool ToBooleanICStub::Types::NeedsMap() const {
3451 return Contains(ToBooleanICStub::SPEC_OBJECT) ||
3452 Contains(ToBooleanICStub::STRING) ||
3453 Contains(ToBooleanICStub::SYMBOL) ||
3454 Contains(ToBooleanICStub::HEAP_NUMBER) ||
3455 Contains(ToBooleanICStub::SIMD_VALUE);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003456}
3457
3458
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003459void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) {
3460 StubFailureTrampolineStub stub1(isolate, NOT_JS_FUNCTION_STUB_MODE);
3461 StubFailureTrampolineStub stub2(isolate, JS_FUNCTION_STUB_MODE);
3462 stub1.GetCode();
3463 stub2.GetCode();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003464}
3465
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003466
3467void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function,
3468 intptr_t stack_pointer,
3469 Isolate* isolate) {
3470 FunctionEntryHook entry_hook = isolate->function_entry_hook();
3471 DCHECK(entry_hook != NULL);
3472 entry_hook(function, stack_pointer);
3473}
3474
3475
3476ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate)
3477 : PlatformCodeStub(isolate) {
3478 minor_key_ = ArgumentCountBits::encode(ANY);
3479 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
3480}
3481
3482
3483ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate,
3484 int argument_count)
3485 : PlatformCodeStub(isolate) {
3486 if (argument_count == 0) {
3487 minor_key_ = ArgumentCountBits::encode(NONE);
3488 } else if (argument_count == 1) {
3489 minor_key_ = ArgumentCountBits::encode(ONE);
3490 } else if (argument_count >= 2) {
3491 minor_key_ = ArgumentCountBits::encode(MORE_THAN_ONE);
3492 } else {
3493 UNREACHABLE();
3494 }
3495 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
3496}
3497
3498
3499InternalArrayConstructorStub::InternalArrayConstructorStub(
3500 Isolate* isolate) : PlatformCodeStub(isolate) {
3501 InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
3502}
3503
3504
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003505Representation RepresentationFromType(Type* type) {
3506 if (type->Is(Type::UntaggedIntegral())) {
3507 return Representation::Integer32();
3508 }
3509
3510 if (type->Is(Type::TaggedSigned())) {
3511 return Representation::Smi();
3512 }
3513
3514 if (type->Is(Type::UntaggedPointer())) {
3515 return Representation::External();
3516 }
3517
3518 DCHECK(!type->Is(Type::Untagged()));
3519 return Representation::Tagged();
3520}
3521
3522} // namespace internal
3523} // namespace v8