blob: d7ea506671401dcfae0c4a13bcf175f60507394c [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Blocka7e24c12009-10-30 11:49:00 +00004
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005#include "src/code-stubs.h"
6
7#include <sstream>
Steve Blocka7e24c12009-10-30 11:49:00 +00008
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#include "src/bootstrapper.h"
Ben Murdochda12d292016-06-02 14:46:10 +010010#include "src/code-factory.h"
Ben Murdochc5610432016-08-08 18:44:38 +010011#include "src/code-stub-assembler.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012#include "src/factory.h"
13#include "src/gdb-jit.h"
14#include "src/ic/handler-compiler.h"
15#include "src/ic/ic.h"
16#include "src/macro-assembler.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017#include "src/parsing/parser.h"
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 {
Ben Murdochc5610432016-08-08 18:44:38 +0100102 return Code::ComputeFlags(GetCodeKind(), GetICState(), GetExtraICState());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100103}
104
105
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000106Handle<Code> CodeStub::GetCodeCopy(const Code::FindAndReplacePattern& pattern) {
107 Handle<Code> ic = GetCode();
108 ic = isolate()->factory()->CopyCode(ic);
109 ic->FindAndReplace(pattern);
110 RecordCodeGeneration(ic);
111 return ic;
112}
113
114
115Handle<Code> PlatformCodeStub::GenerateCode() {
116 Factory* factory = isolate()->factory();
117
118 // Generate the new code.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000119 MacroAssembler masm(isolate(), NULL, 256, CodeObjectRequired::kYes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000120
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000121 {
122 // Update the static counter each time a new code stub is generated.
123 isolate()->counters()->code_stubs()->Increment();
124
125 // Generate the code for the stub.
126 masm.set_generating_stub(true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400127 // TODO(yangguo): remove this once we can serialize IC stubs.
128 masm.enable_serializer();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000129 NoCurrentFrameScope scope(&masm);
130 Generate(&masm);
131 }
132
133 // Create the code object.
134 CodeDesc desc;
135 masm.GetCode(&desc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000136 // Copy the generated code into a heap object.
Ben Murdochc5610432016-08-08 18:44:38 +0100137 Code::Flags flags =
138 Code::ComputeFlags(GetCodeKind(), GetICState(), GetExtraICState());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000139 Handle<Code> new_object = factory->NewCode(
140 desc, flags, masm.CodeObject(), NeedsImmovableCode());
141 return new_object;
142}
143
144
Leon Clarkee46be812010-01-19 14:06:41 +0000145Handle<Code> CodeStub::GetCode() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000146 Heap* heap = isolate()->heap();
Leon Clarkee46be812010-01-19 14:06:41 +0000147 Code* code;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148 if (UseSpecialCache() ? FindCodeInSpecialCache(&code)
149 : FindCodeInCache(&code)) {
150 DCHECK(GetCodeKind() == code->kind());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100151 return Handle<Code>(code);
152 }
153
154 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000155 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000156
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000157 Handle<Code> new_object = GenerateCode();
158 new_object->set_stub_key(GetKey());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100159 FinishCode(new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000160 RecordCodeGeneration(new_object);
161
162#ifdef ENABLE_DISASSEMBLER
163 if (FLAG_print_code_stubs) {
164 CodeTracer::Scope trace_scope(isolate()->GetCodeTracer());
165 OFStream os(trace_scope.file());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400166 std::ostringstream name;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000167 name << *this;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400168 new_object->Disassemble(name.str().c_str(), os);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000169 os << "\n";
170 }
171#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000172
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100173 if (UseSpecialCache()) {
174 AddToSpecialCache(new_object);
175 } else {
176 // Update the dictionary and the root in Heap.
177 Handle<UnseededNumberDictionary> dict =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000178 UnseededNumberDictionary::AtNumberPut(
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100179 Handle<UnseededNumberDictionary>(heap->code_stubs()),
180 GetKey(),
181 new_object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000182 heap->SetRootCodeStubs(*dict);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100183 }
Leon Clarkee46be812010-01-19 14:06:41 +0000184 code = *new_object;
Steve Blocka7e24c12009-10-30 11:49:00 +0000185 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000186
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100187 Activate(code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000188 DCHECK(!NeedsImmovableCode() ||
189 heap->lo_space()->Contains(code) ||
190 heap->code_space()->FirstPage()->Contains(code->address()));
191 return Handle<Code>(code, isolate());
Leon Clarkee46be812010-01-19 14:06:41 +0000192}
193
194
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000195const char* CodeStub::MajorName(CodeStub::Major major_key) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000196 switch (major_key) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000197#define DEF_CASE(name) case name: return #name "Stub";
Steve Blockd0582a62009-12-15 09:54:21 +0000198 CODE_STUB_LIST(DEF_CASE)
199#undef DEF_CASE
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000200 case NoCache:
201 return "<NoCache>Stub";
202 case NUMBER_OF_IDS:
203 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +0000204 return NULL;
205 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000206 return NULL;
207}
208
209
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400210void CodeStub::PrintBaseName(std::ostream& os) const { // NOLINT
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000211 os << MajorName(MajorKey());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000212}
213
214
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400215void CodeStub::PrintName(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000216 PrintBaseName(os);
217 PrintState(os);
218}
219
220
221void CodeStub::Dispatch(Isolate* isolate, uint32_t key, void** value_out,
222 DispatchedCall call) {
223 switch (MajorKeyFromKey(key)) {
224#define DEF_CASE(NAME) \
225 case NAME: { \
226 NAME##Stub stub(key, isolate); \
227 CodeStub* pstub = &stub; \
228 call(pstub, value_out); \
229 break; \
230 }
231 CODE_STUB_LIST(DEF_CASE)
232#undef DEF_CASE
233 case NUMBER_OF_IDS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000234 case NoCache:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400235 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000236 break;
237 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000238}
239
240
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000241static void InitializeDescriptorDispatchedCall(CodeStub* stub,
242 void** value_out) {
243 CodeStubDescriptor* descriptor_out =
244 reinterpret_cast<CodeStubDescriptor*>(value_out);
245 stub->InitializeDescriptor(descriptor_out);
246 descriptor_out->set_call_descriptor(stub->GetCallInterfaceDescriptor());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100247}
248
249
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000250void CodeStub::InitializeDescriptor(Isolate* isolate, uint32_t key,
251 CodeStubDescriptor* desc) {
252 void** value_out = reinterpret_cast<void**>(desc);
253 Dispatch(isolate, key, value_out, &InitializeDescriptorDispatchedCall);
254}
255
256
257void CodeStub::GetCodeDispatchCall(CodeStub* stub, void** value_out) {
258 Handle<Code>* code_out = reinterpret_cast<Handle<Code>*>(value_out);
259 // Code stubs with special cache cannot be recreated from stub key.
260 *code_out = stub->UseSpecialCache() ? Handle<Code>() : stub->GetCode();
261}
262
263
264MaybeHandle<Code> CodeStub::GetCode(Isolate* isolate, uint32_t key) {
265 HandleScope scope(isolate);
266 Handle<Code> code;
267 void** value_out = reinterpret_cast<void**>(&code);
268 Dispatch(isolate, key, value_out, &GetCodeDispatchCall);
269 return scope.CloseAndEscape(code);
270}
271
272
273// static
274void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate) {
275 // Generate the uninitialized versions of the stub.
276 for (int op = Token::BIT_OR; op <= Token::MOD; ++op) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100277 BinaryOpICStub stub(isolate, static_cast<Token::Value>(op));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000278 stub.GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000279 }
280
281 // Generate special versions of the stub.
282 BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
283}
284
285
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400286void BinaryOpICStub::PrintState(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000287 os << state();
288}
289
290
291// static
292void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate,
293 const BinaryOpICState& state) {
294 BinaryOpICStub stub(isolate, state);
295 stub.GetCode();
296}
297
298
299// static
300void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
301 // Generate special versions of the stub.
302 BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
303}
304
305
306void BinaryOpICWithAllocationSiteStub::PrintState(
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400307 std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000308 os << state();
309}
310
311
312// static
313void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(
314 Isolate* isolate, const BinaryOpICState& state) {
315 if (state.CouldCreateAllocationMementos()) {
316 BinaryOpICWithAllocationSiteStub stub(isolate, state);
317 stub.GetCode();
318 }
319}
320
321
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000322std::ostream& operator<<(std::ostream& os, const StringAddFlags& flags) {
323 switch (flags) {
324 case STRING_ADD_CHECK_NONE:
325 return os << "CheckNone";
326 case STRING_ADD_CHECK_LEFT:
327 return os << "CheckLeft";
328 case STRING_ADD_CHECK_RIGHT:
329 return os << "CheckRight";
330 case STRING_ADD_CHECK_BOTH:
331 return os << "CheckBoth";
332 case STRING_ADD_CONVERT_LEFT:
333 return os << "ConvertLeft";
334 case STRING_ADD_CONVERT_RIGHT:
335 return os << "ConvertRight";
336 case STRING_ADD_CONVERT:
337 break;
338 }
339 UNREACHABLE();
340 return os;
341}
342
343
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400344void StringAddStub::PrintBaseName(std::ostream& os) const { // NOLINT
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000345 os << "StringAddStub_" << flags() << "_" << pretenure_flag();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000346}
347
348
349InlineCacheState CompareICStub::GetICState() const {
350 CompareICState::State state = Max(left(), right());
351 switch (state) {
352 case CompareICState::UNINITIALIZED:
353 return ::v8::internal::UNINITIALIZED;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000354 case CompareICState::BOOLEAN:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000355 case CompareICState::SMI:
356 case CompareICState::NUMBER:
357 case CompareICState::INTERNALIZED_STRING:
358 case CompareICState::STRING:
359 case CompareICState::UNIQUE_NAME:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000360 case CompareICState::RECEIVER:
361 case CompareICState::KNOWN_RECEIVER:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000362 return MONOMORPHIC;
363 case CompareICState::GENERIC:
364 return ::v8::internal::GENERIC;
365 }
366 UNREACHABLE();
367 return ::v8::internal::UNINITIALIZED;
368}
369
370
371Condition CompareICStub::GetCondition() const {
372 return CompareIC::ComputeCondition(op());
373}
374
375
376void CompareICStub::AddToSpecialCache(Handle<Code> new_object) {
377 DCHECK(*known_map_ != NULL);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100378 Isolate* isolate = new_object->GetIsolate();
379 Factory* factory = isolate->factory();
380 return Map::UpdateCodeCache(known_map_,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000381 strict() ?
382 factory->strict_compare_ic_string() :
383 factory->compare_ic_string(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100384 new_object);
385}
386
387
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000388bool CompareICStub::FindCodeInSpecialCache(Code** code_out) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100389 Code::Flags flags = Code::ComputeFlags(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000390 GetCodeKind(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100391 UNINITIALIZED);
Ben Murdochc5610432016-08-08 18:44:38 +0100392 Name* name = strict() ? isolate()->heap()->strict_compare_ic_string()
393 : isolate()->heap()->compare_ic_string();
394 Code* code = known_map_->LookupInCodeCache(name, flags);
395 if (code != nullptr) {
396 *code_out = code;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000397#ifdef DEBUG
398 CompareICStub decode((*code_out)->stub_key(), isolate());
399 DCHECK(op() == decode.op());
400 DCHECK(left() == decode.left());
401 DCHECK(right() == decode.right());
402 DCHECK(state() == decode.state());
403#endif
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100404 return true;
405 }
406 return false;
407}
408
409
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000410void CompareICStub::Generate(MacroAssembler* masm) {
411 switch (state()) {
412 case CompareICState::UNINITIALIZED:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100413 GenerateMiss(masm);
414 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000415 case CompareICState::BOOLEAN:
416 GenerateBooleans(masm);
417 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000418 case CompareICState::SMI:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100419 GenerateSmis(masm);
420 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000421 case CompareICState::NUMBER:
422 GenerateNumbers(masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100423 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000424 case CompareICState::STRING:
Ben Murdoch257744e2011-11-30 15:57:28 +0000425 GenerateStrings(masm);
426 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000427 case CompareICState::INTERNALIZED_STRING:
428 GenerateInternalizedStrings(masm);
Ben Murdoch257744e2011-11-30 15:57:28 +0000429 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000430 case CompareICState::UNIQUE_NAME:
431 GenerateUniqueNames(masm);
432 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000433 case CompareICState::RECEIVER:
434 GenerateReceivers(masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100435 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000436 case CompareICState::KNOWN_RECEIVER:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000437 DCHECK(*known_map_ != NULL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000438 GenerateKnownReceivers(masm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100439 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000440 case CompareICState::GENERIC:
441 GenerateGeneric(masm);
442 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100443 }
444}
445
446
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000447Handle<Code> TurboFanCodeStub::GenerateCode() {
448 const char* name = CodeStub::MajorName(MajorKey());
Ben Murdochda12d292016-06-02 14:46:10 +0100449 Zone zone(isolate()->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000450 CallInterfaceDescriptor descriptor(GetCallInterfaceDescriptor());
Ben Murdochc5610432016-08-08 18:44:38 +0100451 CodeStubAssembler assembler(isolate(), &zone, descriptor, GetCodeFlags(),
452 name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000453 GenerateAssembly(&assembler);
454 return assembler.GenerateCode();
455}
456
Ben Murdochda12d292016-06-02 14:46:10 +0100457void AllocateHeapNumberStub::GenerateAssembly(
Ben Murdochc5610432016-08-08 18:44:38 +0100458 CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +0100459 typedef compiler::Node Node;
460
461 Node* result = assembler->AllocateHeapNumber();
462 assembler->Return(result);
463}
464
Ben Murdochda12d292016-06-02 14:46:10 +0100465#define SIMD128_GEN_ASM(TYPE, Type, type, lane_count, lane_type) \
Ben Murdochc5610432016-08-08 18:44:38 +0100466 void Allocate##Type##Stub::GenerateAssembly(CodeStubAssembler* assembler) \
467 const { \
468 compiler::Node* result = \
469 assembler->Allocate(Simd128Value::kSize, CodeStubAssembler::kNone); \
Ben Murdochda12d292016-06-02 14:46:10 +0100470 compiler::Node* map_offset = \
471 assembler->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag); \
472 compiler::Node* map = assembler->IntPtrAdd(result, map_offset); \
473 assembler->StoreNoWriteBarrier( \
474 MachineRepresentation::kTagged, map, \
475 assembler->HeapConstant(isolate()->factory()->type##_map())); \
476 assembler->Return(result); \
477 }
478SIMD128_TYPES(SIMD128_GEN_ASM)
479#undef SIMD128_GEN_ASM
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000480
Ben Murdochc5610432016-08-08 18:44:38 +0100481void StringLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000482 compiler::Node* value = assembler->Parameter(0);
483 compiler::Node* string =
484 assembler->LoadObjectField(value, JSValue::kValueOffset);
485 compiler::Node* result =
486 assembler->LoadObjectField(string, String::kLengthOffset);
487 assembler->Return(result);
488}
489
Ben Murdochc5610432016-08-08 18:44:38 +0100490// static
491compiler::Node* AddStub::Generate(CodeStubAssembler* assembler,
492 compiler::Node* left, compiler::Node* right,
493 compiler::Node* context) {
494 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +0100495 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +0100496 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +0100497
498 // Shared entry for floating point addition.
499 Label do_fadd(assembler);
500 Variable var_fadd_lhs(assembler, MachineRepresentation::kFloat64),
501 var_fadd_rhs(assembler, MachineRepresentation::kFloat64);
502
503 // We might need to loop several times due to ToPrimitive, ToString and/or
504 // ToNumber conversions.
505 Variable var_lhs(assembler, MachineRepresentation::kTagged),
Ben Murdochc5610432016-08-08 18:44:38 +0100506 var_rhs(assembler, MachineRepresentation::kTagged),
507 var_result(assembler, MachineRepresentation::kTagged);
Ben Murdochda12d292016-06-02 14:46:10 +0100508 Variable* loop_vars[2] = {&var_lhs, &var_rhs};
Ben Murdochc5610432016-08-08 18:44:38 +0100509 Label loop(assembler, 2, loop_vars), end(assembler),
510 string_add_convert_left(assembler, Label::kDeferred),
511 string_add_convert_right(assembler, Label::kDeferred);
512 var_lhs.Bind(left);
513 var_rhs.Bind(right);
Ben Murdochda12d292016-06-02 14:46:10 +0100514 assembler->Goto(&loop);
515 assembler->Bind(&loop);
516 {
517 // Load the current {lhs} and {rhs} values.
518 Node* lhs = var_lhs.value();
519 Node* rhs = var_rhs.value();
520
521 // Check if the {lhs} is a Smi or a HeapObject.
522 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
523 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
524
525 assembler->Bind(&if_lhsissmi);
526 {
527 // Check if the {rhs} is also a Smi.
528 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
529 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
530 &if_rhsisnotsmi);
531
532 assembler->Bind(&if_rhsissmi);
533 {
534 // Try fast Smi addition first.
535 Node* pair = assembler->SmiAddWithOverflow(lhs, rhs);
536 Node* overflow = assembler->Projection(1, pair);
537
538 // Check if the Smi additon overflowed.
539 Label if_overflow(assembler), if_notoverflow(assembler);
540 assembler->Branch(overflow, &if_overflow, &if_notoverflow);
541
542 assembler->Bind(&if_overflow);
543 {
544 var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs));
545 var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs));
546 assembler->Goto(&do_fadd);
547 }
548
549 assembler->Bind(&if_notoverflow);
Ben Murdochc5610432016-08-08 18:44:38 +0100550 var_result.Bind(assembler->Projection(0, pair));
551 assembler->Goto(&end);
Ben Murdochda12d292016-06-02 14:46:10 +0100552 }
553
554 assembler->Bind(&if_rhsisnotsmi);
555 {
556 // Load the map of {rhs}.
557 Node* rhs_map = assembler->LoadObjectField(rhs, HeapObject::kMapOffset);
558
559 // Check if the {rhs} is a HeapNumber.
560 Label if_rhsisnumber(assembler),
561 if_rhsisnotnumber(assembler, Label::kDeferred);
562 Node* number_map = assembler->HeapNumberMapConstant();
563 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
564 &if_rhsisnumber, &if_rhsisnotnumber);
565
566 assembler->Bind(&if_rhsisnumber);
567 {
568 var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs));
569 var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
570 assembler->Goto(&do_fadd);
571 }
572
573 assembler->Bind(&if_rhsisnotnumber);
574 {
575 // Load the instance type of {rhs}.
576 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
577
578 // Check if the {rhs} is a String.
579 Label if_rhsisstring(assembler, Label::kDeferred),
580 if_rhsisnotstring(assembler, Label::kDeferred);
581 assembler->Branch(assembler->Int32LessThan(
582 rhs_instance_type,
583 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
584 &if_rhsisstring, &if_rhsisnotstring);
585
586 assembler->Bind(&if_rhsisstring);
587 {
Ben Murdochc5610432016-08-08 18:44:38 +0100588 var_lhs.Bind(lhs);
589 var_rhs.Bind(rhs);
590 assembler->Goto(&string_add_convert_left);
Ben Murdochda12d292016-06-02 14:46:10 +0100591 }
592
593 assembler->Bind(&if_rhsisnotstring);
594 {
595 // Check if {rhs} is a JSReceiver.
596 Label if_rhsisreceiver(assembler, Label::kDeferred),
597 if_rhsisnotreceiver(assembler, Label::kDeferred);
598 assembler->Branch(
599 assembler->Int32LessThanOrEqual(
600 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
601 rhs_instance_type),
602 &if_rhsisreceiver, &if_rhsisnotreceiver);
603
604 assembler->Bind(&if_rhsisreceiver);
605 {
606 // Convert {rhs} to a primitive first passing no hint.
607 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
608 var_rhs.Bind(
609 assembler->CallRuntime(Runtime::kToPrimitive, context, rhs));
610 assembler->Goto(&loop);
611 }
612
613 assembler->Bind(&if_rhsisnotreceiver);
614 {
615 // Convert {rhs} to a Number first.
616 Callable callable =
617 CodeFactory::NonNumberToNumber(assembler->isolate());
618 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
619 assembler->Goto(&loop);
620 }
621 }
622 }
623 }
624 }
625
626 assembler->Bind(&if_lhsisnotsmi);
627 {
628 // Load the map and instance type of {lhs}.
629 Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
630
631 // Check if {lhs} is a String.
632 Label if_lhsisstring(assembler), if_lhsisnotstring(assembler);
633 assembler->Branch(assembler->Int32LessThan(
634 lhs_instance_type,
635 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
636 &if_lhsisstring, &if_lhsisnotstring);
637
638 assembler->Bind(&if_lhsisstring);
639 {
Ben Murdochc5610432016-08-08 18:44:38 +0100640 var_lhs.Bind(lhs);
641 var_rhs.Bind(rhs);
642 assembler->Goto(&string_add_convert_right);
Ben Murdochda12d292016-06-02 14:46:10 +0100643 }
644
645 assembler->Bind(&if_lhsisnotstring);
646 {
647 // Check if {rhs} is a Smi.
648 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
649 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
650 &if_rhsisnotsmi);
651
652 assembler->Bind(&if_rhsissmi);
653 {
654 // Check if {lhs} is a Number.
655 Label if_lhsisnumber(assembler),
656 if_lhsisnotnumber(assembler, Label::kDeferred);
657 assembler->Branch(assembler->Word32Equal(
658 lhs_instance_type,
659 assembler->Int32Constant(HEAP_NUMBER_TYPE)),
660 &if_lhsisnumber, &if_lhsisnotnumber);
661
662 assembler->Bind(&if_lhsisnumber);
663 {
664 // The {lhs} is a HeapNumber, the {rhs} is a Smi, just add them.
665 var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
666 var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs));
667 assembler->Goto(&do_fadd);
668 }
669
670 assembler->Bind(&if_lhsisnotnumber);
671 {
672 // The {lhs} is neither a Number nor a String, and the {rhs} is a
673 // Smi.
674 Label if_lhsisreceiver(assembler, Label::kDeferred),
675 if_lhsisnotreceiver(assembler, Label::kDeferred);
676 assembler->Branch(
677 assembler->Int32LessThanOrEqual(
678 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
679 lhs_instance_type),
680 &if_lhsisreceiver, &if_lhsisnotreceiver);
681
682 assembler->Bind(&if_lhsisreceiver);
683 {
684 // Convert {lhs} to a primitive first passing no hint.
685 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
686 var_lhs.Bind(
687 assembler->CallRuntime(Runtime::kToPrimitive, context, lhs));
688 assembler->Goto(&loop);
689 }
690
691 assembler->Bind(&if_lhsisnotreceiver);
692 {
693 // Convert {lhs} to a Number first.
694 Callable callable =
695 CodeFactory::NonNumberToNumber(assembler->isolate());
696 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
697 assembler->Goto(&loop);
698 }
699 }
700 }
701
702 assembler->Bind(&if_rhsisnotsmi);
703 {
704 // Load the instance type of {rhs}.
705 Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
706
707 // Check if {rhs} is a String.
708 Label if_rhsisstring(assembler), if_rhsisnotstring(assembler);
709 assembler->Branch(assembler->Int32LessThan(
710 rhs_instance_type,
711 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
712 &if_rhsisstring, &if_rhsisnotstring);
713
714 assembler->Bind(&if_rhsisstring);
715 {
Ben Murdochc5610432016-08-08 18:44:38 +0100716 var_lhs.Bind(lhs);
717 var_rhs.Bind(rhs);
718 assembler->Goto(&string_add_convert_left);
Ben Murdochda12d292016-06-02 14:46:10 +0100719 }
720
721 assembler->Bind(&if_rhsisnotstring);
722 {
723 // Check if {lhs} is a HeapNumber.
724 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler);
725 assembler->Branch(assembler->Word32Equal(
726 lhs_instance_type,
727 assembler->Int32Constant(HEAP_NUMBER_TYPE)),
728 &if_lhsisnumber, &if_lhsisnotnumber);
729
730 assembler->Bind(&if_lhsisnumber);
731 {
732 // Check if {rhs} is also a HeapNumber.
733 Label if_rhsisnumber(assembler),
734 if_rhsisnotnumber(assembler, Label::kDeferred);
735 assembler->Branch(assembler->Word32Equal(
736 rhs_instance_type,
737 assembler->Int32Constant(HEAP_NUMBER_TYPE)),
738 &if_rhsisnumber, &if_rhsisnotnumber);
739
740 assembler->Bind(&if_rhsisnumber);
741 {
742 // Perform a floating point addition.
743 var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
744 var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
745 assembler->Goto(&do_fadd);
746 }
747
748 assembler->Bind(&if_rhsisnotnumber);
749 {
750 // Check if {rhs} is a JSReceiver.
751 Label if_rhsisreceiver(assembler, Label::kDeferred),
752 if_rhsisnotreceiver(assembler, Label::kDeferred);
753 assembler->Branch(
754 assembler->Int32LessThanOrEqual(
755 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
756 rhs_instance_type),
757 &if_rhsisreceiver, &if_rhsisnotreceiver);
758
759 assembler->Bind(&if_rhsisreceiver);
760 {
761 // Convert {rhs} to a primitive first passing no hint.
762 // TODO(bmeurer): Hook up ToPrimitiveStub here too.
763 var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
764 context, rhs));
765 assembler->Goto(&loop);
766 }
767
768 assembler->Bind(&if_rhsisnotreceiver);
769 {
770 // Convert {rhs} to a Number first.
771 Callable callable =
772 CodeFactory::NonNumberToNumber(assembler->isolate());
773 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
774 assembler->Goto(&loop);
775 }
776 }
777 }
778
779 assembler->Bind(&if_lhsisnotnumber);
780 {
781 // Check if {lhs} is a JSReceiver.
782 Label if_lhsisreceiver(assembler, Label::kDeferred),
783 if_lhsisnotreceiver(assembler);
784 assembler->Branch(
785 assembler->Int32LessThanOrEqual(
786 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
787 lhs_instance_type),
788 &if_lhsisreceiver, &if_lhsisnotreceiver);
789
790 assembler->Bind(&if_lhsisreceiver);
791 {
792 // Convert {lhs} to a primitive first passing no hint.
793 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
794 var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
795 context, lhs));
796 assembler->Goto(&loop);
797 }
798
799 assembler->Bind(&if_lhsisnotreceiver);
800 {
801 // Check if {rhs} is a JSReceiver.
802 Label if_rhsisreceiver(assembler, Label::kDeferred),
803 if_rhsisnotreceiver(assembler, Label::kDeferred);
804 assembler->Branch(
805 assembler->Int32LessThanOrEqual(
806 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
807 rhs_instance_type),
808 &if_rhsisreceiver, &if_rhsisnotreceiver);
809
810 assembler->Bind(&if_rhsisreceiver);
811 {
812 // Convert {rhs} to a primitive first passing no hint.
813 // TODO(bmeurer): Hook up ToPrimitiveStub here too.
814 var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
815 context, rhs));
816 assembler->Goto(&loop);
817 }
818
819 assembler->Bind(&if_rhsisnotreceiver);
820 {
821 // Convert {lhs} to a Number first.
822 Callable callable =
823 CodeFactory::NonNumberToNumber(assembler->isolate());
824 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
825 assembler->Goto(&loop);
826 }
827 }
828 }
829 }
830 }
831 }
832 }
833 }
Ben Murdochc5610432016-08-08 18:44:38 +0100834 assembler->Bind(&string_add_convert_left);
835 {
836 // Convert {lhs}, which is a Smi, to a String and concatenate the
837 // resulting string with the String {rhs}.
838 Callable callable = CodeFactory::StringAdd(
839 assembler->isolate(), STRING_ADD_CONVERT_LEFT, NOT_TENURED);
840 var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(),
841 var_rhs.value()));
842 assembler->Goto(&end);
843 }
844
845 assembler->Bind(&string_add_convert_right);
846 {
847 // Convert {lhs}, which is a Smi, to a String and concatenate the
848 // resulting string with the String {rhs}.
849 Callable callable = CodeFactory::StringAdd(
850 assembler->isolate(), STRING_ADD_CONVERT_RIGHT, NOT_TENURED);
851 var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(),
852 var_rhs.value()));
853 assembler->Goto(&end);
854 }
Ben Murdochda12d292016-06-02 14:46:10 +0100855
856 assembler->Bind(&do_fadd);
857 {
858 Node* lhs_value = var_fadd_lhs.value();
859 Node* rhs_value = var_fadd_rhs.value();
860 Node* value = assembler->Float64Add(lhs_value, rhs_value);
861 Node* result = assembler->ChangeFloat64ToTagged(value);
Ben Murdochc5610432016-08-08 18:44:38 +0100862 var_result.Bind(result);
863 assembler->Goto(&end);
Ben Murdochda12d292016-06-02 14:46:10 +0100864 }
Ben Murdochc5610432016-08-08 18:44:38 +0100865 assembler->Bind(&end);
866 return var_result.value();
Ben Murdochda12d292016-06-02 14:46:10 +0100867}
868
Ben Murdochc5610432016-08-08 18:44:38 +0100869// static
870compiler::Node* SubtractStub::Generate(CodeStubAssembler* assembler,
871 compiler::Node* left,
872 compiler::Node* right,
873 compiler::Node* context) {
874 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +0100875 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +0100876 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +0100877
878 // Shared entry for floating point subtraction.
Ben Murdochc5610432016-08-08 18:44:38 +0100879 Label do_fsub(assembler), end(assembler);
Ben Murdochda12d292016-06-02 14:46:10 +0100880 Variable var_fsub_lhs(assembler, MachineRepresentation::kFloat64),
881 var_fsub_rhs(assembler, MachineRepresentation::kFloat64);
882
883 // We might need to loop several times due to ToPrimitive and/or ToNumber
884 // conversions.
885 Variable var_lhs(assembler, MachineRepresentation::kTagged),
Ben Murdochc5610432016-08-08 18:44:38 +0100886 var_rhs(assembler, MachineRepresentation::kTagged),
887 var_result(assembler, MachineRepresentation::kTagged);
Ben Murdochda12d292016-06-02 14:46:10 +0100888 Variable* loop_vars[2] = {&var_lhs, &var_rhs};
889 Label loop(assembler, 2, loop_vars);
Ben Murdochc5610432016-08-08 18:44:38 +0100890 var_lhs.Bind(left);
891 var_rhs.Bind(right);
Ben Murdochda12d292016-06-02 14:46:10 +0100892 assembler->Goto(&loop);
893 assembler->Bind(&loop);
894 {
895 // Load the current {lhs} and {rhs} values.
896 Node* lhs = var_lhs.value();
897 Node* rhs = var_rhs.value();
898
899 // Check if the {lhs} is a Smi or a HeapObject.
900 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
901 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
902
903 assembler->Bind(&if_lhsissmi);
904 {
905 // Check if the {rhs} is also a Smi.
906 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
907 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
908 &if_rhsisnotsmi);
909
910 assembler->Bind(&if_rhsissmi);
911 {
912 // Try a fast Smi subtraction first.
913 Node* pair = assembler->SmiSubWithOverflow(lhs, rhs);
914 Node* overflow = assembler->Projection(1, pair);
915
916 // Check if the Smi subtraction overflowed.
917 Label if_overflow(assembler), if_notoverflow(assembler);
918 assembler->Branch(overflow, &if_overflow, &if_notoverflow);
919
920 assembler->Bind(&if_overflow);
921 {
922 // The result doesn't fit into Smi range.
923 var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs));
924 var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs));
925 assembler->Goto(&do_fsub);
926 }
927
928 assembler->Bind(&if_notoverflow);
Ben Murdochc5610432016-08-08 18:44:38 +0100929 var_result.Bind(assembler->Projection(0, pair));
930 assembler->Goto(&end);
Ben Murdochda12d292016-06-02 14:46:10 +0100931 }
932
933 assembler->Bind(&if_rhsisnotsmi);
934 {
935 // Load the map of the {rhs}.
936 Node* rhs_map = assembler->LoadMap(rhs);
937
938 // Check if {rhs} is a HeapNumber.
939 Label if_rhsisnumber(assembler),
940 if_rhsisnotnumber(assembler, Label::kDeferred);
941 Node* number_map = assembler->HeapNumberMapConstant();
942 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
943 &if_rhsisnumber, &if_rhsisnotnumber);
944
945 assembler->Bind(&if_rhsisnumber);
946 {
947 // Perform a floating point subtraction.
948 var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs));
949 var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
950 assembler->Goto(&do_fsub);
951 }
952
953 assembler->Bind(&if_rhsisnotnumber);
954 {
955 // Convert the {rhs} to a Number first.
Ben Murdochc5610432016-08-08 18:44:38 +0100956 Callable callable =
957 CodeFactory::NonNumberToNumber(assembler->isolate());
Ben Murdochda12d292016-06-02 14:46:10 +0100958 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
959 assembler->Goto(&loop);
960 }
961 }
962 }
963
964 assembler->Bind(&if_lhsisnotsmi);
965 {
966 // Load the map of the {lhs}.
967 Node* lhs_map = assembler->LoadMap(lhs);
968
969 // Check if the {lhs} is a HeapNumber.
970 Label if_lhsisnumber(assembler),
971 if_lhsisnotnumber(assembler, Label::kDeferred);
972 Node* number_map = assembler->HeapNumberMapConstant();
973 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
974 &if_lhsisnumber, &if_lhsisnotnumber);
975
976 assembler->Bind(&if_lhsisnumber);
977 {
978 // Check if the {rhs} is a Smi.
979 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
980 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
981 &if_rhsisnotsmi);
982
983 assembler->Bind(&if_rhsissmi);
984 {
985 // Perform a floating point subtraction.
986 var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
987 var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs));
988 assembler->Goto(&do_fsub);
989 }
990
991 assembler->Bind(&if_rhsisnotsmi);
992 {
993 // Load the map of the {rhs}.
994 Node* rhs_map = assembler->LoadMap(rhs);
995
996 // Check if the {rhs} is a HeapNumber.
997 Label if_rhsisnumber(assembler),
998 if_rhsisnotnumber(assembler, Label::kDeferred);
999 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
1000 &if_rhsisnumber, &if_rhsisnotnumber);
1001
1002 assembler->Bind(&if_rhsisnumber);
1003 {
1004 // Perform a floating point subtraction.
1005 var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
1006 var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
1007 assembler->Goto(&do_fsub);
1008 }
1009
1010 assembler->Bind(&if_rhsisnotnumber);
1011 {
1012 // Convert the {rhs} to a Number first.
Ben Murdochc5610432016-08-08 18:44:38 +01001013 Callable callable =
1014 CodeFactory::NonNumberToNumber(assembler->isolate());
Ben Murdochda12d292016-06-02 14:46:10 +01001015 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
1016 assembler->Goto(&loop);
1017 }
1018 }
1019 }
1020
1021 assembler->Bind(&if_lhsisnotnumber);
1022 {
1023 // Convert the {lhs} to a Number first.
Ben Murdochc5610432016-08-08 18:44:38 +01001024 Callable callable =
1025 CodeFactory::NonNumberToNumber(assembler->isolate());
Ben Murdochda12d292016-06-02 14:46:10 +01001026 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
1027 assembler->Goto(&loop);
1028 }
1029 }
1030 }
1031
1032 assembler->Bind(&do_fsub);
1033 {
1034 Node* lhs_value = var_fsub_lhs.value();
1035 Node* rhs_value = var_fsub_rhs.value();
1036 Node* value = assembler->Float64Sub(lhs_value, rhs_value);
Ben Murdochc5610432016-08-08 18:44:38 +01001037 var_result.Bind(assembler->ChangeFloat64ToTagged(value));
1038 assembler->Goto(&end);
1039 }
1040 assembler->Bind(&end);
1041 return var_result.value();
1042}
1043
1044// static
1045compiler::Node* MultiplyStub::Generate(CodeStubAssembler* assembler,
1046 compiler::Node* left,
1047 compiler::Node* right,
1048 compiler::Node* context) {
1049 using compiler::Node;
1050 typedef CodeStubAssembler::Label Label;
1051 typedef CodeStubAssembler::Variable Variable;
1052
1053 // Shared entry point for floating point multiplication.
1054 Label do_fmul(assembler);
1055 Variable var_lhs_float64(assembler, MachineRepresentation::kFloat64),
1056 var_rhs_float64(assembler, MachineRepresentation::kFloat64);
1057
1058 Node* number_map = assembler->HeapNumberMapConstant();
1059
1060 // We might need to loop one or two times due to ToNumber conversions.
1061 Variable var_lhs(assembler, MachineRepresentation::kTagged),
1062 var_rhs(assembler, MachineRepresentation::kTagged);
1063 Variable* loop_variables[] = {&var_lhs, &var_rhs};
1064 Label loop(assembler, 2, loop_variables);
1065 var_lhs.Bind(left);
1066 var_rhs.Bind(right);
1067 assembler->Goto(&loop);
1068 assembler->Bind(&loop);
1069 {
1070 Node* lhs = var_lhs.value();
1071 Node* rhs = var_rhs.value();
1072
1073 Label lhs_is_smi(assembler), lhs_is_not_smi(assembler);
1074 assembler->Branch(assembler->WordIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi);
1075
1076 assembler->Bind(&lhs_is_smi);
1077 {
1078 Label rhs_is_smi(assembler), rhs_is_not_smi(assembler);
1079 assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi,
1080 &rhs_is_not_smi);
1081
1082 assembler->Bind(&rhs_is_smi);
1083 {
1084 // Both {lhs} and {rhs} are Smis. Convert them to double and multiply.
1085 // TODO(epertoso): use SmiMulWithOverflow once available.
1086 var_lhs_float64.Bind(assembler->SmiToFloat64(lhs));
1087 var_rhs_float64.Bind(assembler->SmiToFloat64(rhs));
1088 assembler->Goto(&do_fmul);
1089 }
1090
1091 assembler->Bind(&rhs_is_not_smi);
1092 {
1093 Node* rhs_map = assembler->LoadMap(rhs);
1094
1095 // Check if {rhs} is a HeapNumber.
1096 Label rhs_is_number(assembler),
1097 rhs_is_not_number(assembler, Label::kDeferred);
1098 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
1099 &rhs_is_number, &rhs_is_not_number);
1100
1101 assembler->Bind(&rhs_is_number);
1102 {
1103 // Convert {lhs} to a double and multiply it with the value of {rhs}.
1104 var_lhs_float64.Bind(assembler->SmiToFloat64(lhs));
1105 var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs));
1106 assembler->Goto(&do_fmul);
1107 }
1108
1109 assembler->Bind(&rhs_is_not_number);
1110 {
1111 // Multiplication is commutative, swap {lhs} with {rhs} and loop.
1112 var_lhs.Bind(rhs);
1113 var_rhs.Bind(lhs);
1114 assembler->Goto(&loop);
1115 }
1116 }
1117 }
1118
1119 assembler->Bind(&lhs_is_not_smi);
1120 {
1121 Node* lhs_map = assembler->LoadMap(lhs);
1122
1123 // Check if {lhs} is a HeapNumber.
1124 Label lhs_is_number(assembler),
1125 lhs_is_not_number(assembler, Label::kDeferred);
1126 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
1127 &lhs_is_number, &lhs_is_not_number);
1128
1129 assembler->Bind(&lhs_is_number);
1130 {
1131 // Check if {rhs} is a Smi.
1132 Label rhs_is_smi(assembler), rhs_is_not_smi(assembler);
1133 assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi,
1134 &rhs_is_not_smi);
1135
1136 assembler->Bind(&rhs_is_smi);
1137 {
1138 // Convert {rhs} to a double and multiply it with the value of {lhs}.
1139 var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs));
1140 var_rhs_float64.Bind(assembler->SmiToFloat64(rhs));
1141 assembler->Goto(&do_fmul);
1142 }
1143
1144 assembler->Bind(&rhs_is_not_smi);
1145 {
1146 Node* rhs_map = assembler->LoadMap(rhs);
1147
1148 // Check if {rhs} is a HeapNumber.
1149 Label rhs_is_number(assembler),
1150 rhs_is_not_number(assembler, Label::kDeferred);
1151 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
1152 &rhs_is_number, &rhs_is_not_number);
1153
1154 assembler->Bind(&rhs_is_number);
1155 {
1156 // Both {lhs} and {rhs} are HeapNumbers. Load their values and
1157 // multiply them.
1158 var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs));
1159 var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs));
1160 assembler->Goto(&do_fmul);
1161 }
1162
1163 assembler->Bind(&rhs_is_not_number);
1164 {
1165 // Multiplication is commutative, swap {lhs} with {rhs} and loop.
1166 var_lhs.Bind(rhs);
1167 var_rhs.Bind(lhs);
1168 assembler->Goto(&loop);
1169 }
1170 }
1171 }
1172
1173 assembler->Bind(&lhs_is_not_number);
1174 {
1175 // Convert {lhs} to a Number and loop.
1176 Callable callable =
1177 CodeFactory::NonNumberToNumber(assembler->isolate());
1178 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
1179 assembler->Goto(&loop);
1180 }
1181 }
1182 }
1183
1184 assembler->Bind(&do_fmul);
1185 {
1186 Node* value =
1187 assembler->Float64Mul(var_lhs_float64.value(), var_rhs_float64.value());
Ben Murdochda12d292016-06-02 14:46:10 +01001188 Node* result = assembler->ChangeFloat64ToTagged(value);
Ben Murdochc5610432016-08-08 18:44:38 +01001189 return result;
Ben Murdochda12d292016-06-02 14:46:10 +01001190 }
1191}
1192
Ben Murdochc5610432016-08-08 18:44:38 +01001193// static
1194compiler::Node* DivideStub::Generate(CodeStubAssembler* assembler,
1195 compiler::Node* left,
1196 compiler::Node* right,
1197 compiler::Node* context) {
1198 using compiler::Node;
1199 typedef CodeStubAssembler::Label Label;
1200 typedef CodeStubAssembler::Variable Variable;
1201
1202 // Shared entry point for floating point division.
1203 Label do_fdiv(assembler), end(assembler);
1204 Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64),
1205 var_divisor_float64(assembler, MachineRepresentation::kFloat64);
1206
1207 Node* number_map = assembler->HeapNumberMapConstant();
1208
1209 // We might need to loop one or two times due to ToNumber conversions.
1210 Variable var_dividend(assembler, MachineRepresentation::kTagged),
1211 var_divisor(assembler, MachineRepresentation::kTagged),
1212 var_result(assembler, MachineRepresentation::kTagged);
1213 Variable* loop_variables[] = {&var_dividend, &var_divisor};
1214 Label loop(assembler, 2, loop_variables);
1215 var_dividend.Bind(left);
1216 var_divisor.Bind(right);
1217 assembler->Goto(&loop);
1218 assembler->Bind(&loop);
1219 {
1220 Node* dividend = var_dividend.value();
1221 Node* divisor = var_divisor.value();
1222
1223 Label dividend_is_smi(assembler), dividend_is_not_smi(assembler);
1224 assembler->Branch(assembler->WordIsSmi(dividend), &dividend_is_smi,
1225 &dividend_is_not_smi);
1226
1227 assembler->Bind(&dividend_is_smi);
1228 {
1229 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler);
1230 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi,
1231 &divisor_is_not_smi);
1232
1233 assembler->Bind(&divisor_is_smi);
1234 {
1235 Label bailout(assembler);
1236
1237 // Do floating point division if {divisor} is zero.
1238 assembler->GotoIf(
1239 assembler->WordEqual(divisor, assembler->IntPtrConstant(0)),
1240 &bailout);
1241
1242 // Do floating point division {dividend} is zero and {divisor} is
1243 // negative.
1244 Label dividend_is_zero(assembler), dividend_is_not_zero(assembler);
1245 assembler->Branch(
1246 assembler->WordEqual(dividend, assembler->IntPtrConstant(0)),
1247 &dividend_is_zero, &dividend_is_not_zero);
1248
1249 assembler->Bind(&dividend_is_zero);
1250 {
1251 assembler->GotoIf(
1252 assembler->IntPtrLessThan(divisor, assembler->IntPtrConstant(0)),
1253 &bailout);
1254 assembler->Goto(&dividend_is_not_zero);
1255 }
1256 assembler->Bind(&dividend_is_not_zero);
1257
1258 Node* untagged_divisor = assembler->SmiUntag(divisor);
1259 Node* untagged_dividend = assembler->SmiUntag(dividend);
1260
1261 // Do floating point division if {dividend} is kMinInt (or kMinInt - 1
1262 // if the Smi size is 31) and {divisor} is -1.
1263 Label divisor_is_minus_one(assembler),
1264 divisor_is_not_minus_one(assembler);
1265 assembler->Branch(assembler->Word32Equal(untagged_divisor,
1266 assembler->Int32Constant(-1)),
1267 &divisor_is_minus_one, &divisor_is_not_minus_one);
1268
1269 assembler->Bind(&divisor_is_minus_one);
1270 {
1271 assembler->GotoIf(
1272 assembler->Word32Equal(
1273 untagged_dividend,
1274 assembler->Int32Constant(
1275 kSmiValueSize == 32 ? kMinInt : (kMinInt >> 1))),
1276 &bailout);
1277 assembler->Goto(&divisor_is_not_minus_one);
1278 }
1279 assembler->Bind(&divisor_is_not_minus_one);
1280
1281 // TODO(epertoso): consider adding a machine instruction that returns
1282 // both the result and the remainder.
1283 Node* untagged_result =
1284 assembler->Int32Div(untagged_dividend, untagged_divisor);
1285 Node* truncated =
1286 assembler->IntPtrMul(untagged_result, untagged_divisor);
1287 // Do floating point division if the remainder is not 0.
1288 assembler->GotoIf(
1289 assembler->Word32NotEqual(untagged_dividend, truncated), &bailout);
1290 var_result.Bind(assembler->SmiTag(untagged_result));
1291 assembler->Goto(&end);
1292
1293 // Bailout: convert {dividend} and {divisor} to double and do double
1294 // division.
1295 assembler->Bind(&bailout);
1296 {
1297 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend));
1298 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor));
1299 assembler->Goto(&do_fdiv);
1300 }
1301 }
1302
1303 assembler->Bind(&divisor_is_not_smi);
1304 {
1305 Node* divisor_map = assembler->LoadMap(divisor);
1306
1307 // Check if {divisor} is a HeapNumber.
1308 Label divisor_is_number(assembler),
1309 divisor_is_not_number(assembler, Label::kDeferred);
1310 assembler->Branch(assembler->WordEqual(divisor_map, number_map),
1311 &divisor_is_number, &divisor_is_not_number);
1312
1313 assembler->Bind(&divisor_is_number);
1314 {
1315 // Convert {dividend} to a double and divide it with the value of
1316 // {divisor}.
1317 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend));
1318 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor));
1319 assembler->Goto(&do_fdiv);
1320 }
1321
1322 assembler->Bind(&divisor_is_not_number);
1323 {
1324 // Convert {divisor} to a number and loop.
1325 Callable callable =
1326 CodeFactory::NonNumberToNumber(assembler->isolate());
1327 var_divisor.Bind(assembler->CallStub(callable, context, divisor));
1328 assembler->Goto(&loop);
1329 }
1330 }
1331 }
1332
1333 assembler->Bind(&dividend_is_not_smi);
1334 {
1335 Node* dividend_map = assembler->LoadMap(dividend);
1336
1337 // Check if {dividend} is a HeapNumber.
1338 Label dividend_is_number(assembler),
1339 dividend_is_not_number(assembler, Label::kDeferred);
1340 assembler->Branch(assembler->WordEqual(dividend_map, number_map),
1341 &dividend_is_number, &dividend_is_not_number);
1342
1343 assembler->Bind(&dividend_is_number);
1344 {
1345 // Check if {divisor} is a Smi.
1346 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler);
1347 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi,
1348 &divisor_is_not_smi);
1349
1350 assembler->Bind(&divisor_is_smi);
1351 {
1352 // Convert {divisor} to a double and use it for a floating point
1353 // division.
1354 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend));
1355 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor));
1356 assembler->Goto(&do_fdiv);
1357 }
1358
1359 assembler->Bind(&divisor_is_not_smi);
1360 {
1361 Node* divisor_map = assembler->LoadMap(divisor);
1362
1363 // Check if {divisor} is a HeapNumber.
1364 Label divisor_is_number(assembler),
1365 divisor_is_not_number(assembler, Label::kDeferred);
1366 assembler->Branch(assembler->WordEqual(divisor_map, number_map),
1367 &divisor_is_number, &divisor_is_not_number);
1368
1369 assembler->Bind(&divisor_is_number);
1370 {
1371 // Both {dividend} and {divisor} are HeapNumbers. Load their values
1372 // and divide them.
1373 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend));
1374 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor));
1375 assembler->Goto(&do_fdiv);
1376 }
1377
1378 assembler->Bind(&divisor_is_not_number);
1379 {
1380 // Convert {divisor} to a number and loop.
1381 Callable callable =
1382 CodeFactory::NonNumberToNumber(assembler->isolate());
1383 var_divisor.Bind(assembler->CallStub(callable, context, divisor));
1384 assembler->Goto(&loop);
1385 }
1386 }
1387 }
1388
1389 assembler->Bind(&dividend_is_not_number);
1390 {
1391 // Convert {dividend} to a Number and loop.
1392 Callable callable =
1393 CodeFactory::NonNumberToNumber(assembler->isolate());
1394 var_dividend.Bind(assembler->CallStub(callable, context, dividend));
1395 assembler->Goto(&loop);
1396 }
1397 }
1398 }
1399
1400 assembler->Bind(&do_fdiv);
1401 {
1402 Node* value = assembler->Float64Div(var_dividend_float64.value(),
1403 var_divisor_float64.value());
1404 var_result.Bind(assembler->ChangeFloat64ToTagged(value));
1405 assembler->Goto(&end);
1406 }
1407 assembler->Bind(&end);
1408 return var_result.value();
1409}
1410
1411// static
1412compiler::Node* ModulusStub::Generate(CodeStubAssembler* assembler,
1413 compiler::Node* left,
1414 compiler::Node* right,
1415 compiler::Node* context) {
1416 using compiler::Node;
1417 typedef CodeStubAssembler::Label Label;
1418 typedef CodeStubAssembler::Variable Variable;
1419
1420 // Shared entry point for floating point modulus.
1421 Label do_fmod(assembler);
1422 Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64),
1423 var_divisor_float64(assembler, MachineRepresentation::kFloat64);
1424
1425 Node* number_map = assembler->HeapNumberMapConstant();
1426
1427 // We might need to loop one or two times due to ToNumber conversions.
1428 Variable var_dividend(assembler, MachineRepresentation::kTagged),
1429 var_divisor(assembler, MachineRepresentation::kTagged);
1430 Variable* loop_variables[] = {&var_dividend, &var_divisor};
1431 Label loop(assembler, 2, loop_variables);
1432 var_dividend.Bind(left);
1433 var_divisor.Bind(right);
1434 assembler->Goto(&loop);
1435 assembler->Bind(&loop);
1436 {
1437 Node* dividend = var_dividend.value();
1438 Node* divisor = var_divisor.value();
1439
1440 Label dividend_is_smi(assembler), dividend_is_not_smi(assembler);
1441 assembler->Branch(assembler->WordIsSmi(dividend), &dividend_is_smi,
1442 &dividend_is_not_smi);
1443
1444 assembler->Bind(&dividend_is_smi);
1445 {
1446 Label dividend_is_not_zero(assembler);
1447 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler);
1448 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi,
1449 &divisor_is_not_smi);
1450
1451 assembler->Bind(&divisor_is_smi);
1452 {
1453 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend));
1454 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor));
1455 assembler->Goto(&do_fmod);
1456 }
1457
1458 assembler->Bind(&divisor_is_not_smi);
1459 {
1460 Node* divisor_map = assembler->LoadMap(divisor);
1461
1462 // Check if {divisor} is a HeapNumber.
1463 Label divisor_is_number(assembler),
1464 divisor_is_not_number(assembler, Label::kDeferred);
1465 assembler->Branch(assembler->WordEqual(divisor_map, number_map),
1466 &divisor_is_number, &divisor_is_not_number);
1467
1468 assembler->Bind(&divisor_is_number);
1469 {
1470 // Convert {dividend} to a double and compute its modulus with the
1471 // value of {dividend}.
1472 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend));
1473 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor));
1474 assembler->Goto(&do_fmod);
1475 }
1476
1477 assembler->Bind(&divisor_is_not_number);
1478 {
1479 // Convert {divisor} to a number and loop.
1480 Callable callable =
1481 CodeFactory::NonNumberToNumber(assembler->isolate());
1482 var_divisor.Bind(assembler->CallStub(callable, context, divisor));
1483 assembler->Goto(&loop);
1484 }
1485 }
1486 }
1487
1488 assembler->Bind(&dividend_is_not_smi);
1489 {
1490 Node* dividend_map = assembler->LoadMap(dividend);
1491
1492 // Check if {dividend} is a HeapNumber.
1493 Label dividend_is_number(assembler),
1494 dividend_is_not_number(assembler, Label::kDeferred);
1495 assembler->Branch(assembler->WordEqual(dividend_map, number_map),
1496 &dividend_is_number, &dividend_is_not_number);
1497
1498 assembler->Bind(&dividend_is_number);
1499 {
1500 // Check if {divisor} is a Smi.
1501 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler);
1502 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi,
1503 &divisor_is_not_smi);
1504
1505 assembler->Bind(&divisor_is_smi);
1506 {
1507 // Convert {divisor} to a double and compute {dividend}'s modulus with
1508 // it.
1509 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend));
1510 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor));
1511 assembler->Goto(&do_fmod);
1512 }
1513
1514 assembler->Bind(&divisor_is_not_smi);
1515 {
1516 Node* divisor_map = assembler->LoadMap(divisor);
1517
1518 // Check if {divisor} is a HeapNumber.
1519 Label divisor_is_number(assembler),
1520 divisor_is_not_number(assembler, Label::kDeferred);
1521 assembler->Branch(assembler->WordEqual(divisor_map, number_map),
1522 &divisor_is_number, &divisor_is_not_number);
1523
1524 assembler->Bind(&divisor_is_number);
1525 {
1526 // Both {dividend} and {divisor} are HeapNumbers. Load their values
1527 // and compute their modulus.
1528 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend));
1529 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor));
1530 assembler->Goto(&do_fmod);
1531 }
1532
1533 assembler->Bind(&divisor_is_not_number);
1534 {
1535 // Convert {divisor} to a number and loop.
1536 Callable callable =
1537 CodeFactory::NonNumberToNumber(assembler->isolate());
1538 var_divisor.Bind(assembler->CallStub(callable, context, divisor));
1539 assembler->Goto(&loop);
1540 }
1541 }
1542 }
1543
1544 assembler->Bind(&dividend_is_not_number);
1545 {
1546 // Convert {dividend} to a Number and loop.
1547 Callable callable =
1548 CodeFactory::NonNumberToNumber(assembler->isolate());
1549 var_dividend.Bind(assembler->CallStub(callable, context, dividend));
1550 assembler->Goto(&loop);
1551 }
1552 }
1553 }
1554
1555 assembler->Bind(&do_fmod);
1556 {
1557 Node* value = assembler->Float64Mod(var_dividend_float64.value(),
1558 var_divisor_float64.value());
1559 Node* result = assembler->ChangeFloat64ToTagged(value);
1560 return result;
1561 }
1562}
1563
1564// static
1565compiler::Node* ShiftLeftStub::Generate(CodeStubAssembler* assembler,
1566 compiler::Node* left,
1567 compiler::Node* right,
1568 compiler::Node* context) {
Ben Murdochda12d292016-06-02 14:46:10 +01001569 using compiler::Node;
1570
Ben Murdochc5610432016-08-08 18:44:38 +01001571 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1572 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
1573 Node* shift_count =
1574 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f));
1575 Node* value = assembler->Word32Shl(lhs_value, shift_count);
1576 Node* result = assembler->ChangeInt32ToTagged(value);
1577 return result;
1578}
1579
1580// static
1581compiler::Node* ShiftRightStub::Generate(CodeStubAssembler* assembler,
1582 compiler::Node* left,
1583 compiler::Node* right,
1584 compiler::Node* context) {
1585 using compiler::Node;
1586
1587 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1588 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
1589 Node* shift_count =
1590 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f));
1591 Node* value = assembler->Word32Sar(lhs_value, shift_count);
1592 Node* result = assembler->ChangeInt32ToTagged(value);
1593 return result;
1594}
1595
1596// static
1597compiler::Node* ShiftRightLogicalStub::Generate(CodeStubAssembler* assembler,
1598 compiler::Node* left,
1599 compiler::Node* right,
1600 compiler::Node* context) {
1601 using compiler::Node;
1602
1603 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1604 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
1605 Node* shift_count =
1606 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f));
1607 Node* value = assembler->Word32Shr(lhs_value, shift_count);
1608 Node* result = assembler->ChangeUint32ToTagged(value);
1609 return result;
1610}
1611
1612// static
1613compiler::Node* BitwiseAndStub::Generate(CodeStubAssembler* assembler,
1614 compiler::Node* left,
1615 compiler::Node* right,
1616 compiler::Node* context) {
1617 using compiler::Node;
1618
1619 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1620 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
Ben Murdochda12d292016-06-02 14:46:10 +01001621 Node* value = assembler->Word32And(lhs_value, rhs_value);
1622 Node* result = assembler->ChangeInt32ToTagged(value);
Ben Murdochc5610432016-08-08 18:44:38 +01001623 return result;
Ben Murdochda12d292016-06-02 14:46:10 +01001624}
1625
Ben Murdochc5610432016-08-08 18:44:38 +01001626// static
1627compiler::Node* BitwiseOrStub::Generate(CodeStubAssembler* assembler,
1628 compiler::Node* left,
1629 compiler::Node* right,
1630 compiler::Node* context) {
Ben Murdochda12d292016-06-02 14:46:10 +01001631 using compiler::Node;
1632
Ben Murdochc5610432016-08-08 18:44:38 +01001633 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1634 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
Ben Murdochda12d292016-06-02 14:46:10 +01001635 Node* value = assembler->Word32Or(lhs_value, rhs_value);
1636 Node* result = assembler->ChangeInt32ToTagged(value);
Ben Murdochc5610432016-08-08 18:44:38 +01001637 return result;
Ben Murdochda12d292016-06-02 14:46:10 +01001638}
1639
Ben Murdochc5610432016-08-08 18:44:38 +01001640// static
1641compiler::Node* BitwiseXorStub::Generate(CodeStubAssembler* assembler,
1642 compiler::Node* left,
1643 compiler::Node* right,
1644 compiler::Node* context) {
Ben Murdochda12d292016-06-02 14:46:10 +01001645 using compiler::Node;
1646
Ben Murdochc5610432016-08-08 18:44:38 +01001647 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1648 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
Ben Murdochda12d292016-06-02 14:46:10 +01001649 Node* value = assembler->Word32Xor(lhs_value, rhs_value);
1650 Node* result = assembler->ChangeInt32ToTagged(value);
Ben Murdochc5610432016-08-08 18:44:38 +01001651 return result;
1652}
1653
1654// static
1655compiler::Node* IncStub::Generate(CodeStubAssembler* assembler,
1656 compiler::Node* value,
1657 compiler::Node* context) {
1658 typedef CodeStubAssembler::Label Label;
1659 typedef compiler::Node Node;
1660 typedef CodeStubAssembler::Variable Variable;
1661
1662 // Shared entry for floating point increment.
1663 Label do_finc(assembler), end(assembler);
1664 Variable var_finc_value(assembler, MachineRepresentation::kFloat64);
1665
1666 // We might need to try again due to ToNumber conversion.
1667 Variable value_var(assembler, MachineRepresentation::kTagged);
1668 Variable result_var(assembler, MachineRepresentation::kTagged);
1669 Label start(assembler, &value_var);
1670 value_var.Bind(value);
1671 assembler->Goto(&start);
1672 assembler->Bind(&start);
1673 {
1674 value = value_var.value();
1675
1676 Label if_issmi(assembler), if_isnotsmi(assembler);
1677 assembler->Branch(assembler->WordIsSmi(value), &if_issmi, &if_isnotsmi);
1678
1679 assembler->Bind(&if_issmi);
1680 {
1681 // Try fast Smi addition first.
1682 Node* one = assembler->SmiConstant(Smi::FromInt(1));
1683 Node* pair = assembler->SmiAddWithOverflow(value, one);
1684 Node* overflow = assembler->Projection(1, pair);
1685
1686 // Check if the Smi additon overflowed.
1687 Label if_overflow(assembler), if_notoverflow(assembler);
1688 assembler->Branch(overflow, &if_overflow, &if_notoverflow);
1689
1690 assembler->Bind(&if_notoverflow);
1691 result_var.Bind(assembler->Projection(0, pair));
1692 assembler->Goto(&end);
1693
1694 assembler->Bind(&if_overflow);
1695 {
1696 var_finc_value.Bind(assembler->SmiToFloat64(value));
1697 assembler->Goto(&do_finc);
1698 }
1699 }
1700
1701 assembler->Bind(&if_isnotsmi);
1702 {
1703 // Check if the value is a HeapNumber.
1704 Label if_valueisnumber(assembler),
1705 if_valuenotnumber(assembler, Label::kDeferred);
1706 Node* value_map = assembler->LoadMap(value);
1707 Node* number_map = assembler->HeapNumberMapConstant();
1708 assembler->Branch(assembler->WordEqual(value_map, number_map),
1709 &if_valueisnumber, &if_valuenotnumber);
1710
1711 assembler->Bind(&if_valueisnumber);
1712 {
1713 // Load the HeapNumber value.
1714 var_finc_value.Bind(assembler->LoadHeapNumberValue(value));
1715 assembler->Goto(&do_finc);
1716 }
1717
1718 assembler->Bind(&if_valuenotnumber);
1719 {
1720 // Convert to a Number first and try again.
1721 Callable callable =
1722 CodeFactory::NonNumberToNumber(assembler->isolate());
1723 value_var.Bind(assembler->CallStub(callable, context, value));
1724 assembler->Goto(&start);
1725 }
1726 }
1727 }
1728
1729 assembler->Bind(&do_finc);
1730 {
1731 Node* finc_value = var_finc_value.value();
1732 Node* one = assembler->Float64Constant(1.0);
1733 Node* finc_result = assembler->Float64Add(finc_value, one);
1734 result_var.Bind(assembler->ChangeFloat64ToTagged(finc_result));
1735 assembler->Goto(&end);
1736 }
1737
1738 assembler->Bind(&end);
1739 return result_var.value();
1740}
1741
1742// static
1743compiler::Node* DecStub::Generate(CodeStubAssembler* assembler,
1744 compiler::Node* value,
1745 compiler::Node* context) {
1746 typedef CodeStubAssembler::Label Label;
1747 typedef compiler::Node Node;
1748 typedef CodeStubAssembler::Variable Variable;
1749
1750 // Shared entry for floating point decrement.
1751 Label do_fdec(assembler), end(assembler);
1752 Variable var_fdec_value(assembler, MachineRepresentation::kFloat64);
1753
1754 // We might need to try again due to ToNumber conversion.
1755 Variable value_var(assembler, MachineRepresentation::kTagged);
1756 Variable result_var(assembler, MachineRepresentation::kTagged);
1757 Label start(assembler, &value_var);
1758 value_var.Bind(value);
1759 assembler->Goto(&start);
1760 assembler->Bind(&start);
1761 {
1762 value = value_var.value();
1763
1764 Label if_issmi(assembler), if_isnotsmi(assembler);
1765 assembler->Branch(assembler->WordIsSmi(value), &if_issmi, &if_isnotsmi);
1766
1767 assembler->Bind(&if_issmi);
1768 {
1769 // Try fast Smi subtraction first.
1770 Node* one = assembler->SmiConstant(Smi::FromInt(1));
1771 Node* pair = assembler->SmiSubWithOverflow(value, one);
1772 Node* overflow = assembler->Projection(1, pair);
1773
1774 // Check if the Smi subtraction overflowed.
1775 Label if_overflow(assembler), if_notoverflow(assembler);
1776 assembler->Branch(overflow, &if_overflow, &if_notoverflow);
1777
1778 assembler->Bind(&if_notoverflow);
1779 result_var.Bind(assembler->Projection(0, pair));
1780 assembler->Goto(&end);
1781
1782 assembler->Bind(&if_overflow);
1783 {
1784 var_fdec_value.Bind(assembler->SmiToFloat64(value));
1785 assembler->Goto(&do_fdec);
1786 }
1787 }
1788
1789 assembler->Bind(&if_isnotsmi);
1790 {
1791 // Check if the value is a HeapNumber.
1792 Label if_valueisnumber(assembler),
1793 if_valuenotnumber(assembler, Label::kDeferred);
1794 Node* value_map = assembler->LoadMap(value);
1795 Node* number_map = assembler->HeapNumberMapConstant();
1796 assembler->Branch(assembler->WordEqual(value_map, number_map),
1797 &if_valueisnumber, &if_valuenotnumber);
1798
1799 assembler->Bind(&if_valueisnumber);
1800 {
1801 // Load the HeapNumber value.
1802 var_fdec_value.Bind(assembler->LoadHeapNumberValue(value));
1803 assembler->Goto(&do_fdec);
1804 }
1805
1806 assembler->Bind(&if_valuenotnumber);
1807 {
1808 // Convert to a Number first and try again.
1809 Callable callable =
1810 CodeFactory::NonNumberToNumber(assembler->isolate());
1811 value_var.Bind(assembler->CallStub(callable, context, value));
1812 assembler->Goto(&start);
1813 }
1814 }
1815 }
1816
1817 assembler->Bind(&do_fdec);
1818 {
1819 Node* fdec_value = var_fdec_value.value();
1820 Node* one = assembler->Float64Constant(1.0);
1821 Node* fdec_result = assembler->Float64Sub(fdec_value, one);
1822 result_var.Bind(assembler->ChangeFloat64ToTagged(fdec_result));
1823 assembler->Goto(&end);
1824 }
1825
1826 assembler->Bind(&end);
1827 return result_var.value();
1828}
1829
1830void InstanceOfStub::GenerateAssembly(CodeStubAssembler* assembler) const {
1831 typedef CodeStubAssembler::Label Label;
1832 typedef compiler::Node Node;
1833
1834 Node* object = assembler->Parameter(0);
1835 Node* callable = assembler->Parameter(1);
1836 Node* context = assembler->Parameter(2);
1837
1838 Label return_runtime(assembler, Label::kDeferred);
1839
1840 // Check if no one installed @@hasInstance somewhere.
1841 assembler->GotoUnless(
1842 assembler->WordEqual(
1843 assembler->LoadObjectField(
1844 assembler->LoadRoot(Heap::kHasInstanceProtectorRootIndex),
1845 PropertyCell::kValueOffset),
1846 assembler->SmiConstant(Smi::FromInt(Isolate::kArrayProtectorValid))),
1847 &return_runtime);
1848
1849 // Check if {callable} is a valid receiver.
1850 assembler->GotoIf(assembler->WordIsSmi(callable), &return_runtime);
1851 assembler->GotoIf(
1852 assembler->Word32Equal(
1853 assembler->Word32And(
1854 assembler->LoadMapBitField(assembler->LoadMap(callable)),
1855 assembler->Int32Constant(1 << Map::kIsCallable)),
1856 assembler->Int32Constant(0)),
1857 &return_runtime);
1858
1859 // Use the inline OrdinaryHasInstance directly.
1860 assembler->Return(assembler->OrdinaryHasInstance(context, callable, object));
1861
1862 // TODO(bmeurer): Use GetPropertyStub here once available.
1863 assembler->Bind(&return_runtime);
1864 assembler->TailCallRuntime(Runtime::kInstanceOf, context, object, callable);
Ben Murdochda12d292016-06-02 14:46:10 +01001865}
1866
1867namespace {
1868
1869enum RelationalComparisonMode {
1870 kLessThan,
1871 kLessThanOrEqual,
1872 kGreaterThan,
1873 kGreaterThanOrEqual
1874};
1875
Ben Murdochc5610432016-08-08 18:44:38 +01001876void GenerateAbstractRelationalComparison(CodeStubAssembler* assembler,
1877 RelationalComparisonMode mode) {
1878 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01001879 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +01001880 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +01001881
1882 Node* context = assembler->Parameter(2);
1883
1884 Label return_true(assembler), return_false(assembler);
1885
1886 // Shared entry for floating point comparison.
1887 Label do_fcmp(assembler);
1888 Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64),
1889 var_fcmp_rhs(assembler, MachineRepresentation::kFloat64);
1890
1891 // We might need to loop several times due to ToPrimitive and/or ToNumber
1892 // conversions.
1893 Variable var_lhs(assembler, MachineRepresentation::kTagged),
1894 var_rhs(assembler, MachineRepresentation::kTagged);
1895 Variable* loop_vars[2] = {&var_lhs, &var_rhs};
1896 Label loop(assembler, 2, loop_vars);
1897 var_lhs.Bind(assembler->Parameter(0));
1898 var_rhs.Bind(assembler->Parameter(1));
1899 assembler->Goto(&loop);
1900 assembler->Bind(&loop);
1901 {
1902 // Load the current {lhs} and {rhs} values.
1903 Node* lhs = var_lhs.value();
1904 Node* rhs = var_rhs.value();
1905
1906 // Check if the {lhs} is a Smi or a HeapObject.
1907 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
1908 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
1909
1910 assembler->Bind(&if_lhsissmi);
1911 {
1912 // Check if {rhs} is a Smi or a HeapObject.
1913 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
1914 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
1915 &if_rhsisnotsmi);
1916
1917 assembler->Bind(&if_rhsissmi);
1918 {
1919 // Both {lhs} and {rhs} are Smi, so just perform a fast Smi comparison.
1920 switch (mode) {
1921 case kLessThan:
1922 assembler->BranchIfSmiLessThan(lhs, rhs, &return_true,
1923 &return_false);
1924 break;
1925 case kLessThanOrEqual:
1926 assembler->BranchIfSmiLessThanOrEqual(lhs, rhs, &return_true,
1927 &return_false);
1928 break;
1929 case kGreaterThan:
1930 assembler->BranchIfSmiLessThan(rhs, lhs, &return_true,
1931 &return_false);
1932 break;
1933 case kGreaterThanOrEqual:
1934 assembler->BranchIfSmiLessThanOrEqual(rhs, lhs, &return_true,
1935 &return_false);
1936 break;
1937 }
1938 }
1939
1940 assembler->Bind(&if_rhsisnotsmi);
1941 {
1942 // Load the map of {rhs}.
1943 Node* rhs_map = assembler->LoadMap(rhs);
1944
1945 // Check if the {rhs} is a HeapNumber.
1946 Node* number_map = assembler->HeapNumberMapConstant();
1947 Label if_rhsisnumber(assembler),
1948 if_rhsisnotnumber(assembler, Label::kDeferred);
1949 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
1950 &if_rhsisnumber, &if_rhsisnotnumber);
1951
1952 assembler->Bind(&if_rhsisnumber);
1953 {
1954 // Convert the {lhs} and {rhs} to floating point values, and
1955 // perform a floating point comparison.
1956 var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs));
1957 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
1958 assembler->Goto(&do_fcmp);
1959 }
1960
1961 assembler->Bind(&if_rhsisnotnumber);
1962 {
1963 // Convert the {rhs} to a Number; we don't need to perform the
1964 // dedicated ToPrimitive(rhs, hint Number) operation, as the
1965 // ToNumber(rhs) will by itself already invoke ToPrimitive with
1966 // a Number hint.
1967 Callable callable =
1968 CodeFactory::NonNumberToNumber(assembler->isolate());
1969 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
1970 assembler->Goto(&loop);
1971 }
1972 }
1973 }
1974
1975 assembler->Bind(&if_lhsisnotsmi);
1976 {
1977 // Load the HeapNumber map for later comparisons.
1978 Node* number_map = assembler->HeapNumberMapConstant();
1979
1980 // Load the map of {lhs}.
1981 Node* lhs_map = assembler->LoadMap(lhs);
1982
1983 // Check if {rhs} is a Smi or a HeapObject.
1984 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
1985 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
1986 &if_rhsisnotsmi);
1987
1988 assembler->Bind(&if_rhsissmi);
1989 {
1990 // Check if the {lhs} is a HeapNumber.
1991 Label if_lhsisnumber(assembler),
1992 if_lhsisnotnumber(assembler, Label::kDeferred);
1993 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
1994 &if_lhsisnumber, &if_lhsisnotnumber);
1995
1996 assembler->Bind(&if_lhsisnumber);
1997 {
1998 // Convert the {lhs} and {rhs} to floating point values, and
1999 // perform a floating point comparison.
2000 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
2001 var_fcmp_rhs.Bind(assembler->SmiToFloat64(rhs));
2002 assembler->Goto(&do_fcmp);
2003 }
2004
2005 assembler->Bind(&if_lhsisnotnumber);
2006 {
2007 // Convert the {lhs} to a Number; we don't need to perform the
2008 // dedicated ToPrimitive(lhs, hint Number) operation, as the
2009 // ToNumber(lhs) will by itself already invoke ToPrimitive with
2010 // a Number hint.
2011 Callable callable =
2012 CodeFactory::NonNumberToNumber(assembler->isolate());
2013 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
2014 assembler->Goto(&loop);
2015 }
2016 }
2017
2018 assembler->Bind(&if_rhsisnotsmi);
2019 {
2020 // Load the map of {rhs}.
2021 Node* rhs_map = assembler->LoadMap(rhs);
2022
2023 // Check if {lhs} is a HeapNumber.
2024 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler);
2025 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
2026 &if_lhsisnumber, &if_lhsisnotnumber);
2027
2028 assembler->Bind(&if_lhsisnumber);
2029 {
2030 // Check if {rhs} is also a HeapNumber.
2031 Label if_rhsisnumber(assembler),
2032 if_rhsisnotnumber(assembler, Label::kDeferred);
2033 assembler->Branch(assembler->WordEqual(lhs_map, rhs_map),
2034 &if_rhsisnumber, &if_rhsisnotnumber);
2035
2036 assembler->Bind(&if_rhsisnumber);
2037 {
2038 // Convert the {lhs} and {rhs} to floating point values, and
2039 // perform a floating point comparison.
2040 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
2041 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
2042 assembler->Goto(&do_fcmp);
2043 }
2044
2045 assembler->Bind(&if_rhsisnotnumber);
2046 {
2047 // Convert the {rhs} to a Number; we don't need to perform
2048 // dedicated ToPrimitive(rhs, hint Number) operation, as the
2049 // ToNumber(rhs) will by itself already invoke ToPrimitive with
2050 // a Number hint.
2051 Callable callable =
2052 CodeFactory::NonNumberToNumber(assembler->isolate());
2053 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
2054 assembler->Goto(&loop);
2055 }
2056 }
2057
2058 assembler->Bind(&if_lhsisnotnumber);
2059 {
2060 // Load the instance type of {lhs}.
2061 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map);
2062
2063 // Check if {lhs} is a String.
2064 Label if_lhsisstring(assembler),
2065 if_lhsisnotstring(assembler, Label::kDeferred);
2066 assembler->Branch(assembler->Int32LessThan(
2067 lhs_instance_type,
2068 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
2069 &if_lhsisstring, &if_lhsisnotstring);
2070
2071 assembler->Bind(&if_lhsisstring);
2072 {
2073 // Load the instance type of {rhs}.
2074 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
2075
2076 // Check if {rhs} is also a String.
2077 Label if_rhsisstring(assembler),
2078 if_rhsisnotstring(assembler, Label::kDeferred);
2079 assembler->Branch(assembler->Int32LessThan(
2080 rhs_instance_type, assembler->Int32Constant(
2081 FIRST_NONSTRING_TYPE)),
2082 &if_rhsisstring, &if_rhsisnotstring);
2083
2084 assembler->Bind(&if_rhsisstring);
2085 {
2086 // Both {lhs} and {rhs} are strings.
2087 switch (mode) {
2088 case kLessThan:
2089 assembler->TailCallStub(
2090 CodeFactory::StringLessThan(assembler->isolate()),
2091 context, lhs, rhs);
2092 break;
2093 case kLessThanOrEqual:
2094 assembler->TailCallStub(
2095 CodeFactory::StringLessThanOrEqual(assembler->isolate()),
2096 context, lhs, rhs);
2097 break;
2098 case kGreaterThan:
2099 assembler->TailCallStub(
2100 CodeFactory::StringGreaterThan(assembler->isolate()),
2101 context, lhs, rhs);
2102 break;
2103 case kGreaterThanOrEqual:
2104 assembler->TailCallStub(CodeFactory::StringGreaterThanOrEqual(
2105 assembler->isolate()),
2106 context, lhs, rhs);
2107 break;
2108 }
2109 }
2110
2111 assembler->Bind(&if_rhsisnotstring);
2112 {
2113 // The {lhs} is a String, while {rhs} is neither a Number nor a
2114 // String, so we need to call ToPrimitive(rhs, hint Number) if
2115 // {rhs} is a receiver or ToNumber(lhs) and ToNumber(rhs) in the
2116 // other cases.
2117 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2118 Label if_rhsisreceiver(assembler, Label::kDeferred),
2119 if_rhsisnotreceiver(assembler, Label::kDeferred);
2120 assembler->Branch(
2121 assembler->Int32LessThanOrEqual(
2122 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
2123 rhs_instance_type),
2124 &if_rhsisreceiver, &if_rhsisnotreceiver);
2125
2126 assembler->Bind(&if_rhsisreceiver);
2127 {
2128 // Convert {rhs} to a primitive first passing Number hint.
2129 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
2130 var_rhs.Bind(assembler->CallRuntime(
2131 Runtime::kToPrimitive_Number, context, rhs));
2132 assembler->Goto(&loop);
2133 }
2134
2135 assembler->Bind(&if_rhsisnotreceiver);
2136 {
2137 // Convert both {lhs} and {rhs} to Number.
2138 Callable callable = CodeFactory::ToNumber(assembler->isolate());
2139 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
2140 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
2141 assembler->Goto(&loop);
2142 }
2143 }
2144 }
2145
2146 assembler->Bind(&if_lhsisnotstring);
2147 {
2148 // The {lhs} is neither a Number nor a String, so we need to call
2149 // ToPrimitive(lhs, hint Number) if {lhs} is a receiver or
2150 // ToNumber(lhs) and ToNumber(rhs) in the other cases.
2151 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2152 Label if_lhsisreceiver(assembler, Label::kDeferred),
2153 if_lhsisnotreceiver(assembler, Label::kDeferred);
2154 assembler->Branch(
2155 assembler->Int32LessThanOrEqual(
2156 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
2157 lhs_instance_type),
2158 &if_lhsisreceiver, &if_lhsisnotreceiver);
2159
2160 assembler->Bind(&if_lhsisreceiver);
2161 {
2162 // Convert {lhs} to a primitive first passing Number hint.
2163 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
2164 var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive_Number,
2165 context, lhs));
2166 assembler->Goto(&loop);
2167 }
2168
2169 assembler->Bind(&if_lhsisnotreceiver);
2170 {
2171 // Convert both {lhs} and {rhs} to Number.
2172 Callable callable = CodeFactory::ToNumber(assembler->isolate());
2173 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
2174 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
2175 assembler->Goto(&loop);
2176 }
2177 }
2178 }
2179 }
2180 }
2181 }
2182
2183 assembler->Bind(&do_fcmp);
2184 {
2185 // Load the {lhs} and {rhs} floating point values.
2186 Node* lhs = var_fcmp_lhs.value();
2187 Node* rhs = var_fcmp_rhs.value();
2188
2189 // Perform a fast floating point comparison.
2190 switch (mode) {
2191 case kLessThan:
2192 assembler->BranchIfFloat64LessThan(lhs, rhs, &return_true,
2193 &return_false);
2194 break;
2195 case kLessThanOrEqual:
2196 assembler->BranchIfFloat64LessThanOrEqual(lhs, rhs, &return_true,
2197 &return_false);
2198 break;
2199 case kGreaterThan:
2200 assembler->BranchIfFloat64GreaterThan(lhs, rhs, &return_true,
2201 &return_false);
2202 break;
2203 case kGreaterThanOrEqual:
2204 assembler->BranchIfFloat64GreaterThanOrEqual(lhs, rhs, &return_true,
2205 &return_false);
2206 break;
2207 }
2208 }
2209
2210 assembler->Bind(&return_true);
2211 assembler->Return(assembler->BooleanConstant(true));
2212
2213 assembler->Bind(&return_false);
2214 assembler->Return(assembler->BooleanConstant(false));
2215}
2216
2217enum ResultMode { kDontNegateResult, kNegateResult };
2218
Ben Murdochc5610432016-08-08 18:44:38 +01002219void GenerateEqual_Same(CodeStubAssembler* assembler, compiler::Node* value,
2220 CodeStubAssembler::Label* if_equal,
2221 CodeStubAssembler::Label* if_notequal) {
Ben Murdochda12d292016-06-02 14:46:10 +01002222 // In case of abstract or strict equality checks, we need additional checks
2223 // for NaN values because they are not considered equal, even if both the
2224 // left and the right hand side reference exactly the same value.
2225 // TODO(bmeurer): This seems to violate the SIMD.js specification, but it
2226 // seems to be what is tested in the current SIMD.js testsuite.
2227
Ben Murdochc5610432016-08-08 18:44:38 +01002228 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01002229 typedef compiler::Node Node;
2230
2231 // Check if {value} is a Smi or a HeapObject.
2232 Label if_valueissmi(assembler), if_valueisnotsmi(assembler);
2233 assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi,
2234 &if_valueisnotsmi);
2235
2236 assembler->Bind(&if_valueisnotsmi);
2237 {
2238 // Load the map of {value}.
2239 Node* value_map = assembler->LoadMap(value);
2240
2241 // Check if {value} (and therefore {rhs}) is a HeapNumber.
2242 Node* number_map = assembler->HeapNumberMapConstant();
2243 Label if_valueisnumber(assembler), if_valueisnotnumber(assembler);
2244 assembler->Branch(assembler->WordEqual(value_map, number_map),
2245 &if_valueisnumber, &if_valueisnotnumber);
2246
2247 assembler->Bind(&if_valueisnumber);
2248 {
2249 // Convert {value} (and therefore {rhs}) to floating point value.
2250 Node* value_value = assembler->LoadHeapNumberValue(value);
2251
2252 // Check if the HeapNumber value is a NaN.
2253 assembler->BranchIfFloat64IsNaN(value_value, if_notequal, if_equal);
2254 }
2255
2256 assembler->Bind(&if_valueisnotnumber);
2257 assembler->Goto(if_equal);
2258 }
2259
2260 assembler->Bind(&if_valueissmi);
2261 assembler->Goto(if_equal);
2262}
2263
2264void GenerateEqual_Simd128Value_HeapObject(
Ben Murdochc5610432016-08-08 18:44:38 +01002265 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* lhs_map,
2266 compiler::Node* rhs, compiler::Node* rhs_map,
2267 CodeStubAssembler::Label* if_equal, CodeStubAssembler::Label* if_notequal) {
2268 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01002269 typedef compiler::Node Node;
2270
2271 // Check if {lhs} and {rhs} have the same map.
2272 Label if_mapsame(assembler), if_mapnotsame(assembler);
2273 assembler->Branch(assembler->WordEqual(lhs_map, rhs_map), &if_mapsame,
2274 &if_mapnotsame);
2275
2276 assembler->Bind(&if_mapsame);
2277 {
2278 // Both {lhs} and {rhs} are Simd128Values with the same map, need special
2279 // handling for Float32x4 because of NaN comparisons.
2280 Label if_float32x4(assembler), if_notfloat32x4(assembler);
2281 Node* float32x4_map =
2282 assembler->HeapConstant(assembler->factory()->float32x4_map());
2283 assembler->Branch(assembler->WordEqual(lhs_map, float32x4_map),
2284 &if_float32x4, &if_notfloat32x4);
2285
2286 assembler->Bind(&if_float32x4);
2287 {
2288 // Both {lhs} and {rhs} are Float32x4, compare the lanes individually
2289 // using a floating point comparison.
2290 for (int offset = Float32x4::kValueOffset - kHeapObjectTag;
2291 offset < Float32x4::kSize - kHeapObjectTag;
2292 offset += sizeof(float)) {
2293 // Load the floating point values for {lhs} and {rhs}.
2294 Node* lhs_value = assembler->Load(MachineType::Float32(), lhs,
2295 assembler->IntPtrConstant(offset));
2296 Node* rhs_value = assembler->Load(MachineType::Float32(), rhs,
2297 assembler->IntPtrConstant(offset));
2298
2299 // Perform a floating point comparison.
2300 Label if_valueequal(assembler), if_valuenotequal(assembler);
2301 assembler->Branch(assembler->Float32Equal(lhs_value, rhs_value),
2302 &if_valueequal, &if_valuenotequal);
2303 assembler->Bind(&if_valuenotequal);
2304 assembler->Goto(if_notequal);
2305 assembler->Bind(&if_valueequal);
2306 }
2307
2308 // All 4 lanes match, {lhs} and {rhs} considered equal.
2309 assembler->Goto(if_equal);
2310 }
2311
2312 assembler->Bind(&if_notfloat32x4);
2313 {
2314 // For other Simd128Values we just perform a bitwise comparison.
2315 for (int offset = Simd128Value::kValueOffset - kHeapObjectTag;
2316 offset < Simd128Value::kSize - kHeapObjectTag;
2317 offset += kPointerSize) {
2318 // Load the word values for {lhs} and {rhs}.
2319 Node* lhs_value = assembler->Load(MachineType::Pointer(), lhs,
2320 assembler->IntPtrConstant(offset));
2321 Node* rhs_value = assembler->Load(MachineType::Pointer(), rhs,
2322 assembler->IntPtrConstant(offset));
2323
2324 // Perform a bitwise word-comparison.
2325 Label if_valueequal(assembler), if_valuenotequal(assembler);
2326 assembler->Branch(assembler->WordEqual(lhs_value, rhs_value),
2327 &if_valueequal, &if_valuenotequal);
2328 assembler->Bind(&if_valuenotequal);
2329 assembler->Goto(if_notequal);
2330 assembler->Bind(&if_valueequal);
2331 }
2332
2333 // Bitwise comparison succeeded, {lhs} and {rhs} considered equal.
2334 assembler->Goto(if_equal);
2335 }
2336 }
2337
2338 assembler->Bind(&if_mapnotsame);
2339 assembler->Goto(if_notequal);
2340}
2341
2342// ES6 section 7.2.12 Abstract Equality Comparison
Ben Murdochc5610432016-08-08 18:44:38 +01002343void GenerateEqual(CodeStubAssembler* assembler, ResultMode mode) {
Ben Murdochda12d292016-06-02 14:46:10 +01002344 // This is a slightly optimized version of Object::Equals represented as
2345 // scheduled TurboFan graph utilizing the CodeStubAssembler. Whenever you
2346 // change something functionality wise in here, remember to update the
2347 // Object::Equals method as well.
Ben Murdochc5610432016-08-08 18:44:38 +01002348 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01002349 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +01002350 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +01002351
2352 Node* context = assembler->Parameter(2);
2353
2354 Label if_equal(assembler), if_notequal(assembler);
2355
2356 // Shared entry for floating point comparison.
2357 Label do_fcmp(assembler);
2358 Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64),
2359 var_fcmp_rhs(assembler, MachineRepresentation::kFloat64);
2360
2361 // We might need to loop several times due to ToPrimitive and/or ToNumber
2362 // conversions.
2363 Variable var_lhs(assembler, MachineRepresentation::kTagged),
2364 var_rhs(assembler, MachineRepresentation::kTagged);
2365 Variable* loop_vars[2] = {&var_lhs, &var_rhs};
2366 Label loop(assembler, 2, loop_vars);
2367 var_lhs.Bind(assembler->Parameter(0));
2368 var_rhs.Bind(assembler->Parameter(1));
2369 assembler->Goto(&loop);
2370 assembler->Bind(&loop);
2371 {
2372 // Load the current {lhs} and {rhs} values.
2373 Node* lhs = var_lhs.value();
2374 Node* rhs = var_rhs.value();
2375
2376 // Check if {lhs} and {rhs} refer to the same object.
2377 Label if_same(assembler), if_notsame(assembler);
2378 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
2379
2380 assembler->Bind(&if_same);
2381 {
2382 // The {lhs} and {rhs} reference the exact same value, yet we need special
2383 // treatment for HeapNumber, as NaN is not equal to NaN.
2384 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal);
2385 }
2386
2387 assembler->Bind(&if_notsame);
2388 {
2389 // Check if {lhs} is a Smi or a HeapObject.
2390 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
2391 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi,
2392 &if_lhsisnotsmi);
2393
2394 assembler->Bind(&if_lhsissmi);
2395 {
2396 // Check if {rhs} is a Smi or a HeapObject.
2397 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
2398 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
2399 &if_rhsisnotsmi);
2400
2401 assembler->Bind(&if_rhsissmi);
2402 assembler->Goto(&if_notequal);
2403
2404 assembler->Bind(&if_rhsisnotsmi);
2405 {
2406 // Load the map of {rhs}.
2407 Node* rhs_map = assembler->LoadMap(rhs);
2408
2409 // Check if {rhs} is a HeapNumber.
2410 Node* number_map = assembler->HeapNumberMapConstant();
2411 Label if_rhsisnumber(assembler),
2412 if_rhsisnotnumber(assembler, Label::kDeferred);
2413 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
2414 &if_rhsisnumber, &if_rhsisnotnumber);
2415
2416 assembler->Bind(&if_rhsisnumber);
2417 {
2418 // Convert {lhs} and {rhs} to floating point values, and
2419 // perform a floating point comparison.
2420 var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs));
2421 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
2422 assembler->Goto(&do_fcmp);
2423 }
2424
2425 assembler->Bind(&if_rhsisnotnumber);
2426 {
2427 // Load the instance type of the {rhs}.
2428 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
2429
2430 // Check if the {rhs} is a String.
2431 Label if_rhsisstring(assembler, Label::kDeferred),
2432 if_rhsisnotstring(assembler, Label::kDeferred);
2433 assembler->Branch(assembler->Int32LessThan(
2434 rhs_instance_type, assembler->Int32Constant(
2435 FIRST_NONSTRING_TYPE)),
2436 &if_rhsisstring, &if_rhsisnotstring);
2437
2438 assembler->Bind(&if_rhsisstring);
2439 {
2440 // Convert the {rhs} to a Number.
2441 Callable callable =
2442 CodeFactory::StringToNumber(assembler->isolate());
2443 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
2444 assembler->Goto(&loop);
2445 }
2446
2447 assembler->Bind(&if_rhsisnotstring);
2448 {
2449 // Check if the {rhs} is a Boolean.
2450 Node* boolean_map = assembler->BooleanMapConstant();
2451 Label if_rhsisboolean(assembler, Label::kDeferred),
2452 if_rhsisnotboolean(assembler, Label::kDeferred);
2453 assembler->Branch(assembler->WordEqual(rhs_map, boolean_map),
2454 &if_rhsisboolean, &if_rhsisnotboolean);
2455
2456 assembler->Bind(&if_rhsisboolean);
2457 {
2458 // The {rhs} is a Boolean, load its number value.
2459 var_rhs.Bind(
2460 assembler->LoadObjectField(rhs, Oddball::kToNumberOffset));
2461 assembler->Goto(&loop);
2462 }
2463
2464 assembler->Bind(&if_rhsisnotboolean);
2465 {
2466 // Check if the {rhs} is a Receiver.
2467 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2468 Label if_rhsisreceiver(assembler, Label::kDeferred),
2469 if_rhsisnotreceiver(assembler, Label::kDeferred);
2470 assembler->Branch(
2471 assembler->Int32LessThanOrEqual(
2472 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
2473 rhs_instance_type),
2474 &if_rhsisreceiver, &if_rhsisnotreceiver);
2475
2476 assembler->Bind(&if_rhsisreceiver);
2477 {
2478 // Convert {rhs} to a primitive first (passing no hint).
2479 // TODO(bmeurer): Hook up ToPrimitiveStub here once it exists.
2480 var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
2481 context, rhs));
2482 assembler->Goto(&loop);
2483 }
2484
2485 assembler->Bind(&if_rhsisnotreceiver);
2486 assembler->Goto(&if_notequal);
2487 }
2488 }
2489 }
2490 }
2491 }
2492
2493 assembler->Bind(&if_lhsisnotsmi);
2494 {
2495 // Check if {rhs} is a Smi or a HeapObject.
2496 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
2497 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
2498 &if_rhsisnotsmi);
2499
2500 assembler->Bind(&if_rhsissmi);
2501 {
2502 // The {lhs} is a HeapObject and the {rhs} is a Smi; swapping {lhs}
2503 // and {rhs} is not observable and doesn't matter for the result, so
2504 // we can just swap them and use the Smi handling above (for {lhs}
2505 // being a Smi).
2506 var_lhs.Bind(rhs);
2507 var_rhs.Bind(lhs);
2508 assembler->Goto(&loop);
2509 }
2510
2511 assembler->Bind(&if_rhsisnotsmi);
2512 {
2513 Label if_lhsisstring(assembler), if_lhsisnumber(assembler),
2514 if_lhsissymbol(assembler), if_lhsissimd128value(assembler),
2515 if_lhsisoddball(assembler), if_lhsisreceiver(assembler);
2516
2517 // Both {lhs} and {rhs} are HeapObjects, load their maps
2518 // and their instance types.
2519 Node* lhs_map = assembler->LoadMap(lhs);
2520 Node* rhs_map = assembler->LoadMap(rhs);
2521
2522 // Load the instance types of {lhs} and {rhs}.
2523 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map);
2524 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
2525
2526 // Dispatch based on the instance type of {lhs}.
2527 size_t const kNumCases = FIRST_NONSTRING_TYPE + 4;
2528 Label* case_labels[kNumCases];
2529 int32_t case_values[kNumCases];
2530 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) {
2531 case_labels[i] = new Label(assembler);
2532 case_values[i] = i;
2533 }
2534 case_labels[FIRST_NONSTRING_TYPE + 0] = &if_lhsisnumber;
2535 case_values[FIRST_NONSTRING_TYPE + 0] = HEAP_NUMBER_TYPE;
2536 case_labels[FIRST_NONSTRING_TYPE + 1] = &if_lhsissymbol;
2537 case_values[FIRST_NONSTRING_TYPE + 1] = SYMBOL_TYPE;
2538 case_labels[FIRST_NONSTRING_TYPE + 2] = &if_lhsissimd128value;
2539 case_values[FIRST_NONSTRING_TYPE + 2] = SIMD128_VALUE_TYPE;
2540 case_labels[FIRST_NONSTRING_TYPE + 3] = &if_lhsisoddball;
2541 case_values[FIRST_NONSTRING_TYPE + 3] = ODDBALL_TYPE;
2542 assembler->Switch(lhs_instance_type, &if_lhsisreceiver, case_values,
2543 case_labels, arraysize(case_values));
2544 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) {
2545 assembler->Bind(case_labels[i]);
2546 assembler->Goto(&if_lhsisstring);
2547 delete case_labels[i];
2548 }
2549
2550 assembler->Bind(&if_lhsisstring);
2551 {
2552 // Check if {rhs} is also a String.
2553 Label if_rhsisstring(assembler),
2554 if_rhsisnotstring(assembler, Label::kDeferred);
2555 assembler->Branch(assembler->Int32LessThan(
2556 rhs_instance_type, assembler->Int32Constant(
2557 FIRST_NONSTRING_TYPE)),
2558 &if_rhsisstring, &if_rhsisnotstring);
2559
2560 assembler->Bind(&if_rhsisstring);
2561 {
2562 // Both {lhs} and {rhs} are of type String, just do the
2563 // string comparison then.
2564 Callable callable =
2565 (mode == kDontNegateResult)
2566 ? CodeFactory::StringEqual(assembler->isolate())
2567 : CodeFactory::StringNotEqual(assembler->isolate());
2568 assembler->TailCallStub(callable, context, lhs, rhs);
2569 }
2570
2571 assembler->Bind(&if_rhsisnotstring);
2572 {
2573 // The {lhs} is a String and the {rhs} is some other HeapObject.
2574 // Swapping {lhs} and {rhs} is not observable and doesn't matter
2575 // for the result, so we can just swap them and use the String
2576 // handling below (for {rhs} being a String).
2577 var_lhs.Bind(rhs);
2578 var_rhs.Bind(lhs);
2579 assembler->Goto(&loop);
2580 }
2581 }
2582
2583 assembler->Bind(&if_lhsisnumber);
2584 {
2585 // Check if {rhs} is also a HeapNumber.
2586 Label if_rhsisnumber(assembler),
2587 if_rhsisnotnumber(assembler, Label::kDeferred);
2588 assembler->Branch(
2589 assembler->Word32Equal(lhs_instance_type, rhs_instance_type),
2590 &if_rhsisnumber, &if_rhsisnotnumber);
2591
2592 assembler->Bind(&if_rhsisnumber);
2593 {
2594 // Convert {lhs} and {rhs} to floating point values, and
2595 // perform a floating point comparison.
2596 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
2597 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
2598 assembler->Goto(&do_fcmp);
2599 }
2600
2601 assembler->Bind(&if_rhsisnotnumber);
2602 {
2603 // The {lhs} is a Number, the {rhs} is some other HeapObject.
2604 Label if_rhsisstring(assembler, Label::kDeferred),
2605 if_rhsisnotstring(assembler);
2606 assembler->Branch(
2607 assembler->Int32LessThan(
2608 rhs_instance_type,
2609 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
2610 &if_rhsisstring, &if_rhsisnotstring);
2611
2612 assembler->Bind(&if_rhsisstring);
2613 {
2614 // The {rhs} is a String and the {lhs} is a HeapNumber; we need
2615 // to convert the {rhs} to a Number and compare the output to
2616 // the Number on the {lhs}.
2617 Callable callable =
2618 CodeFactory::StringToNumber(assembler->isolate());
2619 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
2620 assembler->Goto(&loop);
2621 }
2622
2623 assembler->Bind(&if_rhsisnotstring);
2624 {
2625 // Check if the {rhs} is a JSReceiver.
2626 Label if_rhsisreceiver(assembler, Label::kDeferred),
2627 if_rhsisnotreceiver(assembler);
2628 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
2629 assembler->Branch(
2630 assembler->Int32LessThanOrEqual(
2631 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
2632 rhs_instance_type),
2633 &if_rhsisreceiver, &if_rhsisnotreceiver);
2634
2635 assembler->Bind(&if_rhsisreceiver);
2636 {
2637 // The {lhs} is a Primitive and the {rhs} is a JSReceiver.
2638 // Swapping {lhs} and {rhs} is not observable and doesn't
2639 // matter for the result, so we can just swap them and use
2640 // the JSReceiver handling below (for {lhs} being a
2641 // JSReceiver).
2642 var_lhs.Bind(rhs);
2643 var_rhs.Bind(lhs);
2644 assembler->Goto(&loop);
2645 }
2646
2647 assembler->Bind(&if_rhsisnotreceiver);
2648 {
2649 // Check if {rhs} is a Boolean.
2650 Label if_rhsisboolean(assembler),
2651 if_rhsisnotboolean(assembler);
2652 Node* boolean_map = assembler->BooleanMapConstant();
2653 assembler->Branch(assembler->WordEqual(rhs_map, boolean_map),
2654 &if_rhsisboolean, &if_rhsisnotboolean);
2655
2656 assembler->Bind(&if_rhsisboolean);
2657 {
2658 // The {rhs} is a Boolean, convert it to a Smi first.
2659 var_rhs.Bind(assembler->LoadObjectField(
2660 rhs, Oddball::kToNumberOffset));
2661 assembler->Goto(&loop);
2662 }
2663
2664 assembler->Bind(&if_rhsisnotboolean);
2665 assembler->Goto(&if_notequal);
2666 }
2667 }
2668 }
2669 }
2670
2671 assembler->Bind(&if_lhsisoddball);
2672 {
2673 // The {lhs} is an Oddball and {rhs} is some other HeapObject.
2674 Label if_lhsisboolean(assembler), if_lhsisnotboolean(assembler);
2675 Node* boolean_map = assembler->BooleanMapConstant();
2676 assembler->Branch(assembler->WordEqual(lhs_map, boolean_map),
2677 &if_lhsisboolean, &if_lhsisnotboolean);
2678
2679 assembler->Bind(&if_lhsisboolean);
2680 {
2681 // The {lhs} is a Boolean, check if {rhs} is also a Boolean.
2682 Label if_rhsisboolean(assembler), if_rhsisnotboolean(assembler);
2683 assembler->Branch(assembler->WordEqual(rhs_map, boolean_map),
2684 &if_rhsisboolean, &if_rhsisnotboolean);
2685
2686 assembler->Bind(&if_rhsisboolean);
2687 {
2688 // Both {lhs} and {rhs} are distinct Boolean values.
2689 assembler->Goto(&if_notequal);
2690 }
2691
2692 assembler->Bind(&if_rhsisnotboolean);
2693 {
2694 // Convert the {lhs} to a Number first.
2695 var_lhs.Bind(
2696 assembler->LoadObjectField(lhs, Oddball::kToNumberOffset));
2697 assembler->Goto(&loop);
2698 }
2699 }
2700
2701 assembler->Bind(&if_lhsisnotboolean);
2702 {
2703 // The {lhs} is either Null or Undefined; check if the {rhs} is
2704 // undetectable (i.e. either also Null or Undefined or some
2705 // undetectable JSReceiver).
2706 Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map);
2707 assembler->BranchIfWord32Equal(
2708 assembler->Word32And(
2709 rhs_bitfield,
2710 assembler->Int32Constant(1 << Map::kIsUndetectable)),
2711 assembler->Int32Constant(0), &if_notequal, &if_equal);
2712 }
2713 }
2714
2715 assembler->Bind(&if_lhsissymbol);
2716 {
2717 // Check if the {rhs} is a JSReceiver.
2718 Label if_rhsisreceiver(assembler, Label::kDeferred),
2719 if_rhsisnotreceiver(assembler);
2720 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
2721 assembler->Branch(
2722 assembler->Int32LessThanOrEqual(
2723 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
2724 rhs_instance_type),
2725 &if_rhsisreceiver, &if_rhsisnotreceiver);
2726
2727 assembler->Bind(&if_rhsisreceiver);
2728 {
2729 // The {lhs} is a Primitive and the {rhs} is a JSReceiver.
2730 // Swapping {lhs} and {rhs} is not observable and doesn't
2731 // matter for the result, so we can just swap them and use
2732 // the JSReceiver handling below (for {lhs} being a JSReceiver).
2733 var_lhs.Bind(rhs);
2734 var_rhs.Bind(lhs);
2735 assembler->Goto(&loop);
2736 }
2737
2738 assembler->Bind(&if_rhsisnotreceiver);
2739 {
2740 // The {rhs} is not a JSReceiver and also not the same Symbol
2741 // as the {lhs}, so this is equality check is considered false.
2742 assembler->Goto(&if_notequal);
2743 }
2744 }
2745
2746 assembler->Bind(&if_lhsissimd128value);
2747 {
2748 // Check if the {rhs} is also a Simd128Value.
2749 Label if_rhsissimd128value(assembler),
2750 if_rhsisnotsimd128value(assembler);
2751 assembler->Branch(
2752 assembler->Word32Equal(lhs_instance_type, rhs_instance_type),
2753 &if_rhsissimd128value, &if_rhsisnotsimd128value);
2754
2755 assembler->Bind(&if_rhsissimd128value);
2756 {
2757 // Both {lhs} and {rhs} is a Simd128Value.
2758 GenerateEqual_Simd128Value_HeapObject(assembler, lhs, lhs_map,
2759 rhs, rhs_map, &if_equal,
2760 &if_notequal);
2761 }
2762
2763 assembler->Bind(&if_rhsisnotsimd128value);
2764 {
2765 // Check if the {rhs} is a JSReceiver.
2766 Label if_rhsisreceiver(assembler, Label::kDeferred),
2767 if_rhsisnotreceiver(assembler);
2768 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
2769 assembler->Branch(
2770 assembler->Int32LessThanOrEqual(
2771 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
2772 rhs_instance_type),
2773 &if_rhsisreceiver, &if_rhsisnotreceiver);
2774
2775 assembler->Bind(&if_rhsisreceiver);
2776 {
2777 // The {lhs} is a Primitive and the {rhs} is a JSReceiver.
2778 // Swapping {lhs} and {rhs} is not observable and doesn't
2779 // matter for the result, so we can just swap them and use
2780 // the JSReceiver handling below (for {lhs} being a JSReceiver).
2781 var_lhs.Bind(rhs);
2782 var_rhs.Bind(lhs);
2783 assembler->Goto(&loop);
2784 }
2785
2786 assembler->Bind(&if_rhsisnotreceiver);
2787 {
2788 // The {rhs} is some other Primitive.
2789 assembler->Goto(&if_notequal);
2790 }
2791 }
2792 }
2793
2794 assembler->Bind(&if_lhsisreceiver);
2795 {
2796 // Check if the {rhs} is also a JSReceiver.
2797 Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler);
2798 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
2799 assembler->Branch(
2800 assembler->Int32LessThanOrEqual(
2801 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
2802 rhs_instance_type),
2803 &if_rhsisreceiver, &if_rhsisnotreceiver);
2804
2805 assembler->Bind(&if_rhsisreceiver);
2806 {
2807 // Both {lhs} and {rhs} are different JSReceiver references, so
2808 // this cannot be considered equal.
2809 assembler->Goto(&if_notequal);
2810 }
2811
2812 assembler->Bind(&if_rhsisnotreceiver);
2813 {
2814 // Check if {rhs} is Null or Undefined (an undetectable check
2815 // is sufficient here, since we already know that {rhs} is not
2816 // a JSReceiver).
2817 Label if_rhsisundetectable(assembler),
2818 if_rhsisnotundetectable(assembler, Label::kDeferred);
2819 Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map);
2820 assembler->BranchIfWord32Equal(
2821 assembler->Word32And(
2822 rhs_bitfield,
2823 assembler->Int32Constant(1 << Map::kIsUndetectable)),
2824 assembler->Int32Constant(0), &if_rhsisnotundetectable,
2825 &if_rhsisundetectable);
2826
2827 assembler->Bind(&if_rhsisundetectable);
2828 {
2829 // Check if {lhs} is an undetectable JSReceiver.
2830 Node* lhs_bitfield = assembler->LoadMapBitField(lhs_map);
2831 assembler->BranchIfWord32Equal(
2832 assembler->Word32And(
2833 lhs_bitfield,
2834 assembler->Int32Constant(1 << Map::kIsUndetectable)),
2835 assembler->Int32Constant(0), &if_notequal, &if_equal);
2836 }
2837
2838 assembler->Bind(&if_rhsisnotundetectable);
2839 {
2840 // The {rhs} is some Primitive different from Null and
2841 // Undefined, need to convert {lhs} to Primitive first.
2842 // TODO(bmeurer): Hook up ToPrimitiveStub here once it exists.
2843 var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
2844 context, lhs));
2845 assembler->Goto(&loop);
2846 }
2847 }
2848 }
2849 }
2850 }
2851 }
2852 }
2853
2854 assembler->Bind(&do_fcmp);
2855 {
2856 // Load the {lhs} and {rhs} floating point values.
2857 Node* lhs = var_fcmp_lhs.value();
2858 Node* rhs = var_fcmp_rhs.value();
2859
2860 // Perform a fast floating point comparison.
2861 assembler->BranchIfFloat64Equal(lhs, rhs, &if_equal, &if_notequal);
2862 }
2863
2864 assembler->Bind(&if_equal);
2865 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult));
2866
2867 assembler->Bind(&if_notequal);
2868 assembler->Return(assembler->BooleanConstant(mode == kNegateResult));
2869}
2870
Ben Murdochc5610432016-08-08 18:44:38 +01002871void GenerateStrictEqual(CodeStubAssembler* assembler, ResultMode mode) {
Ben Murdochda12d292016-06-02 14:46:10 +01002872 // Here's pseudo-code for the algorithm below in case of kDontNegateResult
2873 // mode; for kNegateResult mode we properly negate the result.
2874 //
2875 // if (lhs == rhs) {
2876 // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN;
2877 // return true;
2878 // }
2879 // if (!lhs->IsSmi()) {
2880 // if (lhs->IsHeapNumber()) {
2881 // if (rhs->IsSmi()) {
2882 // return Smi::cast(rhs)->value() == HeapNumber::cast(lhs)->value();
2883 // } else if (rhs->IsHeapNumber()) {
2884 // return HeapNumber::cast(rhs)->value() ==
2885 // HeapNumber::cast(lhs)->value();
2886 // } else {
2887 // return false;
2888 // }
2889 // } else {
2890 // if (rhs->IsSmi()) {
2891 // return false;
2892 // } else {
2893 // if (lhs->IsString()) {
2894 // if (rhs->IsString()) {
2895 // return %StringEqual(lhs, rhs);
2896 // } else {
2897 // return false;
2898 // }
2899 // } else if (lhs->IsSimd128()) {
2900 // if (rhs->IsSimd128()) {
2901 // return %StrictEqual(lhs, rhs);
2902 // }
2903 // } else {
2904 // return false;
2905 // }
2906 // }
2907 // }
2908 // } else {
2909 // if (rhs->IsSmi()) {
2910 // return false;
2911 // } else {
2912 // if (rhs->IsHeapNumber()) {
2913 // return Smi::cast(lhs)->value() == HeapNumber::cast(rhs)->value();
2914 // } else {
2915 // return false;
2916 // }
2917 // }
2918 // }
2919
Ben Murdochc5610432016-08-08 18:44:38 +01002920 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01002921 typedef compiler::Node Node;
2922
2923 Node* lhs = assembler->Parameter(0);
2924 Node* rhs = assembler->Parameter(1);
2925 Node* context = assembler->Parameter(2);
2926
2927 Label if_equal(assembler), if_notequal(assembler);
2928
2929 // Check if {lhs} and {rhs} refer to the same object.
2930 Label if_same(assembler), if_notsame(assembler);
2931 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
2932
2933 assembler->Bind(&if_same);
2934 {
2935 // The {lhs} and {rhs} reference the exact same value, yet we need special
2936 // treatment for HeapNumber, as NaN is not equal to NaN.
2937 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal);
2938 }
2939
2940 assembler->Bind(&if_notsame);
2941 {
2942 // The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber,
2943 // String and Simd128Value they can still be considered equal.
2944 Node* number_map = assembler->HeapNumberMapConstant();
2945
2946 // Check if {lhs} is a Smi or a HeapObject.
2947 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
2948 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
2949
2950 assembler->Bind(&if_lhsisnotsmi);
2951 {
2952 // Load the map of {lhs}.
2953 Node* lhs_map = assembler->LoadMap(lhs);
2954
2955 // Check if {lhs} is a HeapNumber.
2956 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler);
2957 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
2958 &if_lhsisnumber, &if_lhsisnotnumber);
2959
2960 assembler->Bind(&if_lhsisnumber);
2961 {
2962 // Check if {rhs} is a Smi or a HeapObject.
2963 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
2964 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
2965 &if_rhsisnotsmi);
2966
2967 assembler->Bind(&if_rhsissmi);
2968 {
2969 // Convert {lhs} and {rhs} to floating point values.
2970 Node* lhs_value = assembler->LoadHeapNumberValue(lhs);
2971 Node* rhs_value = assembler->SmiToFloat64(rhs);
2972
2973 // Perform a floating point comparison of {lhs} and {rhs}.
2974 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal,
2975 &if_notequal);
2976 }
2977
2978 assembler->Bind(&if_rhsisnotsmi);
2979 {
2980 // Load the map of {rhs}.
2981 Node* rhs_map = assembler->LoadMap(rhs);
2982
2983 // Check if {rhs} is also a HeapNumber.
2984 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler);
2985 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
2986 &if_rhsisnumber, &if_rhsisnotnumber);
2987
2988 assembler->Bind(&if_rhsisnumber);
2989 {
2990 // Convert {lhs} and {rhs} to floating point values.
2991 Node* lhs_value = assembler->LoadHeapNumberValue(lhs);
2992 Node* rhs_value = assembler->LoadHeapNumberValue(rhs);
2993
2994 // Perform a floating point comparison of {lhs} and {rhs}.
2995 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal,
2996 &if_notequal);
2997 }
2998
2999 assembler->Bind(&if_rhsisnotnumber);
3000 assembler->Goto(&if_notequal);
3001 }
3002 }
3003
3004 assembler->Bind(&if_lhsisnotnumber);
3005 {
3006 // Check if {rhs} is a Smi or a HeapObject.
3007 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
3008 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
3009 &if_rhsisnotsmi);
3010
3011 assembler->Bind(&if_rhsissmi);
3012 assembler->Goto(&if_notequal);
3013
3014 assembler->Bind(&if_rhsisnotsmi);
3015 {
3016 // Load the instance type of {lhs}.
3017 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map);
3018
3019 // Check if {lhs} is a String.
3020 Label if_lhsisstring(assembler), if_lhsisnotstring(assembler);
3021 assembler->Branch(assembler->Int32LessThan(
3022 lhs_instance_type,
3023 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
3024 &if_lhsisstring, &if_lhsisnotstring);
3025
3026 assembler->Bind(&if_lhsisstring);
3027 {
3028 // Load the instance type of {rhs}.
3029 Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
3030
3031 // Check if {rhs} is also a String.
3032 Label if_rhsisstring(assembler), if_rhsisnotstring(assembler);
3033 assembler->Branch(assembler->Int32LessThan(
3034 rhs_instance_type, assembler->Int32Constant(
3035 FIRST_NONSTRING_TYPE)),
3036 &if_rhsisstring, &if_rhsisnotstring);
3037
3038 assembler->Bind(&if_rhsisstring);
3039 {
3040 Callable callable =
3041 (mode == kDontNegateResult)
3042 ? CodeFactory::StringEqual(assembler->isolate())
3043 : CodeFactory::StringNotEqual(assembler->isolate());
3044 assembler->TailCallStub(callable, context, lhs, rhs);
3045 }
3046
3047 assembler->Bind(&if_rhsisnotstring);
3048 assembler->Goto(&if_notequal);
3049 }
3050
3051 assembler->Bind(&if_lhsisnotstring);
3052 {
3053 // Check if {lhs} is a Simd128Value.
3054 Label if_lhsissimd128value(assembler),
3055 if_lhsisnotsimd128value(assembler);
3056 assembler->Branch(assembler->Word32Equal(
3057 lhs_instance_type,
3058 assembler->Int32Constant(SIMD128_VALUE_TYPE)),
3059 &if_lhsissimd128value, &if_lhsisnotsimd128value);
3060
3061 assembler->Bind(&if_lhsissimd128value);
3062 {
3063 // Load the map of {rhs}.
3064 Node* rhs_map = assembler->LoadMap(rhs);
3065
3066 // Check if {rhs} is also a Simd128Value that is equal to {lhs}.
3067 GenerateEqual_Simd128Value_HeapObject(assembler, lhs, lhs_map,
3068 rhs, rhs_map, &if_equal,
3069 &if_notequal);
3070 }
3071
3072 assembler->Bind(&if_lhsisnotsimd128value);
3073 assembler->Goto(&if_notequal);
3074 }
3075 }
3076 }
3077 }
3078
3079 assembler->Bind(&if_lhsissmi);
3080 {
3081 // We already know that {lhs} and {rhs} are not reference equal, and {lhs}
3082 // is a Smi; so {lhs} and {rhs} can only be strictly equal if {rhs} is a
3083 // HeapNumber with an equal floating point value.
3084
3085 // Check if {rhs} is a Smi or a HeapObject.
3086 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
3087 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
3088 &if_rhsisnotsmi);
3089
3090 assembler->Bind(&if_rhsissmi);
3091 assembler->Goto(&if_notequal);
3092
3093 assembler->Bind(&if_rhsisnotsmi);
3094 {
3095 // Load the map of the {rhs}.
3096 Node* rhs_map = assembler->LoadMap(rhs);
3097
3098 // The {rhs} could be a HeapNumber with the same value as {lhs}.
3099 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler);
3100 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
3101 &if_rhsisnumber, &if_rhsisnotnumber);
3102
3103 assembler->Bind(&if_rhsisnumber);
3104 {
3105 // Convert {lhs} and {rhs} to floating point values.
3106 Node* lhs_value = assembler->SmiToFloat64(lhs);
3107 Node* rhs_value = assembler->LoadHeapNumberValue(rhs);
3108
3109 // Perform a floating point comparison of {lhs} and {rhs}.
3110 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal,
3111 &if_notequal);
3112 }
3113
3114 assembler->Bind(&if_rhsisnotnumber);
3115 assembler->Goto(&if_notequal);
3116 }
3117 }
3118 }
3119
3120 assembler->Bind(&if_equal);
3121 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult));
3122
3123 assembler->Bind(&if_notequal);
3124 assembler->Return(assembler->BooleanConstant(mode == kNegateResult));
3125}
3126
Ben Murdochc5610432016-08-08 18:44:38 +01003127void GenerateStringRelationalComparison(CodeStubAssembler* assembler,
Ben Murdochda12d292016-06-02 14:46:10 +01003128 RelationalComparisonMode mode) {
Ben Murdochc5610432016-08-08 18:44:38 +01003129 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01003130 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +01003131 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +01003132
3133 Node* lhs = assembler->Parameter(0);
3134 Node* rhs = assembler->Parameter(1);
3135 Node* context = assembler->Parameter(2);
3136
3137 Label if_less(assembler), if_equal(assembler), if_greater(assembler);
3138
3139 // Fast check to see if {lhs} and {rhs} refer to the same String object.
3140 Label if_same(assembler), if_notsame(assembler);
3141 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
3142
3143 assembler->Bind(&if_same);
3144 assembler->Goto(&if_equal);
3145
3146 assembler->Bind(&if_notsame);
3147 {
3148 // Load instance types of {lhs} and {rhs}.
3149 Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
3150 Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
3151
3152 // Combine the instance types into a single 16-bit value, so we can check
3153 // both of them at once.
3154 Node* both_instance_types = assembler->Word32Or(
3155 lhs_instance_type,
3156 assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
3157
3158 // Check that both {lhs} and {rhs} are flat one-byte strings.
3159 int const kBothSeqOneByteStringMask =
3160 kStringEncodingMask | kStringRepresentationMask |
3161 ((kStringEncodingMask | kStringRepresentationMask) << 8);
3162 int const kBothSeqOneByteStringTag =
3163 kOneByteStringTag | kSeqStringTag |
3164 ((kOneByteStringTag | kSeqStringTag) << 8);
3165 Label if_bothonebyteseqstrings(assembler),
3166 if_notbothonebyteseqstrings(assembler);
3167 assembler->Branch(assembler->Word32Equal(
3168 assembler->Word32And(both_instance_types,
3169 assembler->Int32Constant(
3170 kBothSeqOneByteStringMask)),
3171 assembler->Int32Constant(kBothSeqOneByteStringTag)),
3172 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
3173
3174 assembler->Bind(&if_bothonebyteseqstrings);
3175 {
3176 // Load the length of {lhs} and {rhs}.
3177 Node* lhs_length = assembler->LoadObjectField(lhs, String::kLengthOffset);
3178 Node* rhs_length = assembler->LoadObjectField(rhs, String::kLengthOffset);
3179
3180 // Determine the minimum length.
3181 Node* length = assembler->SmiMin(lhs_length, rhs_length);
3182
3183 // Compute the effective offset of the first character.
3184 Node* begin = assembler->IntPtrConstant(SeqOneByteString::kHeaderSize -
3185 kHeapObjectTag);
3186
3187 // Compute the first offset after the string from the length.
3188 Node* end = assembler->IntPtrAdd(begin, assembler->SmiUntag(length));
3189
3190 // Loop over the {lhs} and {rhs} strings to see if they are equal.
3191 Variable var_offset(assembler, MachineType::PointerRepresentation());
3192 Label loop(assembler, &var_offset);
3193 var_offset.Bind(begin);
3194 assembler->Goto(&loop);
3195 assembler->Bind(&loop);
3196 {
3197 // Check if {offset} equals {end}.
3198 Node* offset = var_offset.value();
3199 Label if_done(assembler), if_notdone(assembler);
3200 assembler->Branch(assembler->WordEqual(offset, end), &if_done,
3201 &if_notdone);
3202
3203 assembler->Bind(&if_notdone);
3204 {
3205 // Load the next characters from {lhs} and {rhs}.
3206 Node* lhs_value = assembler->Load(MachineType::Uint8(), lhs, offset);
3207 Node* rhs_value = assembler->Load(MachineType::Uint8(), rhs, offset);
3208
3209 // Check if the characters match.
3210 Label if_valueissame(assembler), if_valueisnotsame(assembler);
3211 assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
3212 &if_valueissame, &if_valueisnotsame);
3213
3214 assembler->Bind(&if_valueissame);
3215 {
3216 // Advance to next character.
3217 var_offset.Bind(
3218 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
3219 }
3220 assembler->Goto(&loop);
3221
3222 assembler->Bind(&if_valueisnotsame);
3223 assembler->BranchIf(assembler->Uint32LessThan(lhs_value, rhs_value),
3224 &if_less, &if_greater);
3225 }
3226
3227 assembler->Bind(&if_done);
3228 {
3229 // All characters up to the min length are equal, decide based on
3230 // string length.
3231 Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
3232 assembler->Branch(assembler->SmiEqual(lhs_length, rhs_length),
3233 &if_lengthisequal, &if_lengthisnotequal);
3234
3235 assembler->Bind(&if_lengthisequal);
3236 assembler->Goto(&if_equal);
3237
3238 assembler->Bind(&if_lengthisnotequal);
3239 assembler->BranchIfSmiLessThan(lhs_length, rhs_length, &if_less,
3240 &if_greater);
3241 }
3242 }
3243 }
3244
3245 assembler->Bind(&if_notbothonebyteseqstrings);
3246 {
3247 // TODO(bmeurer): Add fast case support for flattened cons strings;
3248 // also add support for two byte string relational comparisons.
3249 switch (mode) {
3250 case kLessThan:
3251 assembler->TailCallRuntime(Runtime::kStringLessThan, context, lhs,
3252 rhs);
3253 break;
3254 case kLessThanOrEqual:
3255 assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual, context,
3256 lhs, rhs);
3257 break;
3258 case kGreaterThan:
3259 assembler->TailCallRuntime(Runtime::kStringGreaterThan, context, lhs,
3260 rhs);
3261 break;
3262 case kGreaterThanOrEqual:
3263 assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual,
3264 context, lhs, rhs);
3265 break;
3266 }
3267 }
3268 }
3269
3270 assembler->Bind(&if_less);
3271 switch (mode) {
3272 case kLessThan:
3273 case kLessThanOrEqual:
3274 assembler->Return(assembler->BooleanConstant(true));
3275 break;
3276
3277 case kGreaterThan:
3278 case kGreaterThanOrEqual:
3279 assembler->Return(assembler->BooleanConstant(false));
3280 break;
3281 }
3282
3283 assembler->Bind(&if_equal);
3284 switch (mode) {
3285 case kLessThan:
3286 case kGreaterThan:
3287 assembler->Return(assembler->BooleanConstant(false));
3288 break;
3289
3290 case kLessThanOrEqual:
3291 case kGreaterThanOrEqual:
3292 assembler->Return(assembler->BooleanConstant(true));
3293 break;
3294 }
3295
3296 assembler->Bind(&if_greater);
3297 switch (mode) {
3298 case kLessThan:
3299 case kLessThanOrEqual:
3300 assembler->Return(assembler->BooleanConstant(false));
3301 break;
3302
3303 case kGreaterThan:
3304 case kGreaterThanOrEqual:
3305 assembler->Return(assembler->BooleanConstant(true));
3306 break;
3307 }
3308}
3309
Ben Murdochc5610432016-08-08 18:44:38 +01003310void GenerateStringEqual(CodeStubAssembler* assembler, ResultMode mode) {
Ben Murdochda12d292016-06-02 14:46:10 +01003311 // Here's pseudo-code for the algorithm below in case of kDontNegateResult
3312 // mode; for kNegateResult mode we properly negate the result.
3313 //
3314 // if (lhs == rhs) return true;
3315 // if (lhs->length() != rhs->length()) return false;
3316 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) {
3317 // return false;
3318 // }
3319 // if (lhs->IsSeqOneByteString() && rhs->IsSeqOneByteString()) {
3320 // for (i = 0; i != lhs->length(); ++i) {
3321 // if (lhs[i] != rhs[i]) return false;
3322 // }
3323 // return true;
3324 // }
3325 // return %StringEqual(lhs, rhs);
3326
Ben Murdochc5610432016-08-08 18:44:38 +01003327 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01003328 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +01003329 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +01003330
3331 Node* lhs = assembler->Parameter(0);
3332 Node* rhs = assembler->Parameter(1);
3333 Node* context = assembler->Parameter(2);
3334
3335 Label if_equal(assembler), if_notequal(assembler);
3336
3337 // Fast check to see if {lhs} and {rhs} refer to the same String object.
3338 Label if_same(assembler), if_notsame(assembler);
3339 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
3340
3341 assembler->Bind(&if_same);
3342 assembler->Goto(&if_equal);
3343
3344 assembler->Bind(&if_notsame);
3345 {
3346 // The {lhs} and {rhs} don't refer to the exact same String object.
3347
3348 // Load the length of {lhs} and {rhs}.
3349 Node* lhs_length = assembler->LoadObjectField(lhs, String::kLengthOffset);
3350 Node* rhs_length = assembler->LoadObjectField(rhs, String::kLengthOffset);
3351
3352 // Check if the lengths of {lhs} and {rhs} are equal.
3353 Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
3354 assembler->Branch(assembler->WordEqual(lhs_length, rhs_length),
3355 &if_lengthisequal, &if_lengthisnotequal);
3356
3357 assembler->Bind(&if_lengthisequal);
3358 {
3359 // Load instance types of {lhs} and {rhs}.
3360 Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
3361 Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
3362
3363 // Combine the instance types into a single 16-bit value, so we can check
3364 // both of them at once.
3365 Node* both_instance_types = assembler->Word32Or(
3366 lhs_instance_type,
3367 assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
3368
3369 // Check if both {lhs} and {rhs} are internalized.
3370 int const kBothInternalizedMask =
3371 kIsNotInternalizedMask | (kIsNotInternalizedMask << 8);
3372 int const kBothInternalizedTag =
3373 kInternalizedTag | (kInternalizedTag << 8);
3374 Label if_bothinternalized(assembler), if_notbothinternalized(assembler);
3375 assembler->Branch(assembler->Word32Equal(
3376 assembler->Word32And(both_instance_types,
3377 assembler->Int32Constant(
3378 kBothInternalizedMask)),
3379 assembler->Int32Constant(kBothInternalizedTag)),
3380 &if_bothinternalized, &if_notbothinternalized);
3381
3382 assembler->Bind(&if_bothinternalized);
3383 {
3384 // Fast negative check for internalized-to-internalized equality.
3385 assembler->Goto(&if_notequal);
3386 }
3387
3388 assembler->Bind(&if_notbothinternalized);
3389 {
3390 // Check that both {lhs} and {rhs} are flat one-byte strings.
3391 int const kBothSeqOneByteStringMask =
3392 kStringEncodingMask | kStringRepresentationMask |
3393 ((kStringEncodingMask | kStringRepresentationMask) << 8);
3394 int const kBothSeqOneByteStringTag =
3395 kOneByteStringTag | kSeqStringTag |
3396 ((kOneByteStringTag | kSeqStringTag) << 8);
3397 Label if_bothonebyteseqstrings(assembler),
3398 if_notbothonebyteseqstrings(assembler);
3399 assembler->Branch(
3400 assembler->Word32Equal(
3401 assembler->Word32And(
3402 both_instance_types,
3403 assembler->Int32Constant(kBothSeqOneByteStringMask)),
3404 assembler->Int32Constant(kBothSeqOneByteStringTag)),
3405 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
3406
3407 assembler->Bind(&if_bothonebyteseqstrings);
3408 {
3409 // Compute the effective offset of the first character.
3410 Node* begin = assembler->IntPtrConstant(
3411 SeqOneByteString::kHeaderSize - kHeapObjectTag);
3412
3413 // Compute the first offset after the string from the length.
3414 Node* end =
3415 assembler->IntPtrAdd(begin, assembler->SmiUntag(lhs_length));
3416
3417 // Loop over the {lhs} and {rhs} strings to see if they are equal.
3418 Variable var_offset(assembler, MachineType::PointerRepresentation());
3419 Label loop(assembler, &var_offset);
3420 var_offset.Bind(begin);
3421 assembler->Goto(&loop);
3422 assembler->Bind(&loop);
3423 {
3424 // Check if {offset} equals {end}.
3425 Node* offset = var_offset.value();
3426 Label if_done(assembler), if_notdone(assembler);
3427 assembler->Branch(assembler->WordEqual(offset, end), &if_done,
3428 &if_notdone);
3429
3430 assembler->Bind(&if_notdone);
3431 {
3432 // Load the next characters from {lhs} and {rhs}.
3433 Node* lhs_value =
3434 assembler->Load(MachineType::Uint8(), lhs, offset);
3435 Node* rhs_value =
3436 assembler->Load(MachineType::Uint8(), rhs, offset);
3437
3438 // Check if the characters match.
3439 Label if_valueissame(assembler), if_valueisnotsame(assembler);
3440 assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
3441 &if_valueissame, &if_valueisnotsame);
3442
3443 assembler->Bind(&if_valueissame);
3444 {
3445 // Advance to next character.
3446 var_offset.Bind(
3447 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
3448 }
3449 assembler->Goto(&loop);
3450
3451 assembler->Bind(&if_valueisnotsame);
3452 assembler->Goto(&if_notequal);
3453 }
3454
3455 assembler->Bind(&if_done);
3456 assembler->Goto(&if_equal);
3457 }
3458 }
3459
3460 assembler->Bind(&if_notbothonebyteseqstrings);
3461 {
3462 // TODO(bmeurer): Add fast case support for flattened cons strings;
3463 // also add support for two byte string equality checks.
3464 Runtime::FunctionId function_id = (mode == kDontNegateResult)
3465 ? Runtime::kStringEqual
3466 : Runtime::kStringNotEqual;
3467 assembler->TailCallRuntime(function_id, context, lhs, rhs);
3468 }
3469 }
3470 }
3471
3472 assembler->Bind(&if_lengthisnotequal);
3473 {
3474 // Mismatch in length of {lhs} and {rhs}, cannot be equal.
3475 assembler->Goto(&if_notequal);
3476 }
3477 }
3478
3479 assembler->Bind(&if_equal);
3480 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult));
3481
3482 assembler->Bind(&if_notequal);
3483 assembler->Return(assembler->BooleanConstant(mode == kNegateResult));
3484}
3485
3486} // namespace
3487
Ben Murdochc5610432016-08-08 18:44:38 +01003488void LoadApiGetterStub::GenerateAssembly(CodeStubAssembler* assembler) const {
3489 typedef compiler::Node Node;
3490 Node* context = assembler->Parameter(3);
3491 Node* receiver = assembler->Parameter(0);
3492 // For now we only support receiver_is_holder.
3493 DCHECK(receiver_is_holder());
3494 Node* holder = receiver;
3495 Node* map = assembler->LoadMap(receiver);
3496 Node* descriptors = assembler->LoadMapDescriptors(map);
3497 Node* offset =
3498 assembler->Int32Constant(DescriptorArray::ToValueIndex(index()));
3499 Node* callback = assembler->LoadFixedArrayElement(descriptors, offset);
3500 assembler->TailCallStub(CodeFactory::ApiGetter(isolate()), context, receiver,
3501 holder, callback);
3502}
3503
3504void LessThanStub::GenerateAssembly(CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003505 GenerateAbstractRelationalComparison(assembler, kLessThan);
3506}
3507
Ben Murdochc5610432016-08-08 18:44:38 +01003508void LessThanOrEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003509 GenerateAbstractRelationalComparison(assembler, kLessThanOrEqual);
3510}
3511
Ben Murdochc5610432016-08-08 18:44:38 +01003512void GreaterThanStub::GenerateAssembly(CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003513 GenerateAbstractRelationalComparison(assembler, kGreaterThan);
3514}
3515
3516void GreaterThanOrEqualStub::GenerateAssembly(
Ben Murdochc5610432016-08-08 18:44:38 +01003517 CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003518 GenerateAbstractRelationalComparison(assembler, kGreaterThanOrEqual);
3519}
3520
Ben Murdochc5610432016-08-08 18:44:38 +01003521void EqualStub::GenerateAssembly(CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003522 GenerateEqual(assembler, kDontNegateResult);
3523}
3524
Ben Murdochc5610432016-08-08 18:44:38 +01003525void NotEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003526 GenerateEqual(assembler, kNegateResult);
3527}
3528
Ben Murdochc5610432016-08-08 18:44:38 +01003529void StrictEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003530 GenerateStrictEqual(assembler, kDontNegateResult);
3531}
3532
Ben Murdochc5610432016-08-08 18:44:38 +01003533void StrictNotEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003534 GenerateStrictEqual(assembler, kNegateResult);
3535}
3536
Ben Murdochc5610432016-08-08 18:44:38 +01003537void StringEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003538 GenerateStringEqual(assembler, kDontNegateResult);
3539}
3540
Ben Murdochc5610432016-08-08 18:44:38 +01003541void StringNotEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003542 GenerateStringEqual(assembler, kNegateResult);
3543}
3544
Ben Murdochc5610432016-08-08 18:44:38 +01003545void StringLessThanStub::GenerateAssembly(CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003546 GenerateStringRelationalComparison(assembler, kLessThan);
3547}
3548
3549void StringLessThanOrEqualStub::GenerateAssembly(
Ben Murdochc5610432016-08-08 18:44:38 +01003550 CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003551 GenerateStringRelationalComparison(assembler, kLessThanOrEqual);
3552}
3553
3554void StringGreaterThanStub::GenerateAssembly(
Ben Murdochc5610432016-08-08 18:44:38 +01003555 CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003556 GenerateStringRelationalComparison(assembler, kGreaterThan);
3557}
3558
3559void StringGreaterThanOrEqualStub::GenerateAssembly(
Ben Murdochc5610432016-08-08 18:44:38 +01003560 CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003561 GenerateStringRelationalComparison(assembler, kGreaterThanOrEqual);
3562}
3563
Ben Murdochc5610432016-08-08 18:44:38 +01003564void ToLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const {
3565 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01003566 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +01003567 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +01003568
3569 Node* context = assembler->Parameter(1);
3570
3571 // We might need to loop once for ToNumber conversion.
3572 Variable var_len(assembler, MachineRepresentation::kTagged);
3573 Label loop(assembler, &var_len);
3574 var_len.Bind(assembler->Parameter(0));
3575 assembler->Goto(&loop);
3576 assembler->Bind(&loop);
3577 {
3578 // Shared entry points.
3579 Label return_len(assembler),
3580 return_two53minus1(assembler, Label::kDeferred),
3581 return_zero(assembler, Label::kDeferred);
3582
3583 // Load the current {len} value.
3584 Node* len = var_len.value();
3585
3586 // Check if {len} is a positive Smi.
3587 assembler->GotoIf(assembler->WordIsPositiveSmi(len), &return_len);
3588
3589 // Check if {len} is a (negative) Smi.
3590 assembler->GotoIf(assembler->WordIsSmi(len), &return_zero);
3591
3592 // Check if {len} is a HeapNumber.
3593 Label if_lenisheapnumber(assembler),
3594 if_lenisnotheapnumber(assembler, Label::kDeferred);
3595 assembler->Branch(assembler->WordEqual(assembler->LoadMap(len),
3596 assembler->HeapNumberMapConstant()),
3597 &if_lenisheapnumber, &if_lenisnotheapnumber);
3598
3599 assembler->Bind(&if_lenisheapnumber);
3600 {
3601 // Load the floating-point value of {len}.
3602 Node* len_value = assembler->LoadHeapNumberValue(len);
3603
3604 // Check if {len} is not greater than zero.
3605 assembler->GotoUnless(assembler->Float64GreaterThan(
3606 len_value, assembler->Float64Constant(0.0)),
3607 &return_zero);
3608
3609 // Check if {len} is greater than or equal to 2^53-1.
3610 assembler->GotoIf(
3611 assembler->Float64GreaterThanOrEqual(
3612 len_value, assembler->Float64Constant(kMaxSafeInteger)),
3613 &return_two53minus1);
3614
3615 // Round the {len} towards -Infinity.
3616 Node* value = assembler->Float64Floor(len_value);
3617 Node* result = assembler->ChangeFloat64ToTagged(value);
3618 assembler->Return(result);
3619 }
3620
3621 assembler->Bind(&if_lenisnotheapnumber);
3622 {
3623 // Need to convert {len} to a Number first.
3624 Callable callable = CodeFactory::NonNumberToNumber(assembler->isolate());
3625 var_len.Bind(assembler->CallStub(callable, context, len));
3626 assembler->Goto(&loop);
3627 }
3628
3629 assembler->Bind(&return_len);
3630 assembler->Return(var_len.value());
3631
3632 assembler->Bind(&return_two53minus1);
3633 assembler->Return(assembler->NumberConstant(kMaxSafeInteger));
3634
3635 assembler->Bind(&return_zero);
3636 assembler->Return(assembler->SmiConstant(Smi::FromInt(0)));
3637 }
3638}
3639
Ben Murdochc5610432016-08-08 18:44:38 +01003640void ToBooleanStub::GenerateAssembly(CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003641 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +01003642 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01003643
3644 Node* value = assembler->Parameter(0);
Ben Murdochc5610432016-08-08 18:44:38 +01003645 Label if_valueissmi(assembler), if_valueisnotsmi(assembler),
3646 return_true(assembler), return_false(assembler);
Ben Murdochda12d292016-06-02 14:46:10 +01003647
3648 // Check if {value} is a Smi or a HeapObject.
3649 assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi,
3650 &if_valueisnotsmi);
3651
3652 assembler->Bind(&if_valueissmi);
3653 {
3654 // The {value} is a Smi, only need to check against zero.
Ben Murdochda12d292016-06-02 14:46:10 +01003655 assembler->Branch(assembler->SmiEqual(value, assembler->SmiConstant(0)),
Ben Murdochc5610432016-08-08 18:44:38 +01003656 &return_false, &return_true);
Ben Murdochda12d292016-06-02 14:46:10 +01003657 }
3658
3659 assembler->Bind(&if_valueisnotsmi);
3660 {
Ben Murdochc5610432016-08-08 18:44:38 +01003661 Label if_valueisstring(assembler), if_valueisnotstring(assembler),
3662 if_valueisheapnumber(assembler), if_valueisoddball(assembler),
3663 if_valueisother(assembler);
Ben Murdochda12d292016-06-02 14:46:10 +01003664
3665 // The {value} is a HeapObject, load its map.
3666 Node* value_map = assembler->LoadMap(value);
3667
3668 // Load the {value}s instance type.
3669 Node* value_instance_type = assembler->Load(
3670 MachineType::Uint8(), value_map,
3671 assembler->IntPtrConstant(Map::kInstanceTypeOffset - kHeapObjectTag));
3672
3673 // Dispatch based on the instance type; we distinguish all String instance
3674 // types, the HeapNumber type and the Oddball type.
Ben Murdochc5610432016-08-08 18:44:38 +01003675 assembler->Branch(assembler->Int32LessThan(
3676 value_instance_type,
3677 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
3678 &if_valueisstring, &if_valueisnotstring);
3679 assembler->Bind(&if_valueisnotstring);
3680 size_t const kNumCases = 2;
Ben Murdochda12d292016-06-02 14:46:10 +01003681 Label* case_labels[kNumCases];
3682 int32_t case_values[kNumCases];
Ben Murdochc5610432016-08-08 18:44:38 +01003683 case_labels[0] = &if_valueisheapnumber;
3684 case_values[0] = HEAP_NUMBER_TYPE;
3685 case_labels[1] = &if_valueisoddball;
3686 case_values[1] = ODDBALL_TYPE;
Ben Murdochda12d292016-06-02 14:46:10 +01003687 assembler->Switch(value_instance_type, &if_valueisother, case_values,
3688 case_labels, arraysize(case_values));
Ben Murdochda12d292016-06-02 14:46:10 +01003689
3690 assembler->Bind(&if_valueisstring);
3691 {
3692 // Load the string length field of the {value}.
3693 Node* value_length =
3694 assembler->LoadObjectField(value, String::kLengthOffset);
3695
3696 // Check if the {value} is the empty string.
Ben Murdochda12d292016-06-02 14:46:10 +01003697 assembler->Branch(
3698 assembler->SmiEqual(value_length, assembler->SmiConstant(0)),
Ben Murdochc5610432016-08-08 18:44:38 +01003699 &return_false, &return_true);
Ben Murdochda12d292016-06-02 14:46:10 +01003700 }
3701
3702 assembler->Bind(&if_valueisheapnumber);
3703 {
3704 Node* value_value = assembler->Load(
3705 MachineType::Float64(), value,
3706 assembler->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag));
3707
Ben Murdochc5610432016-08-08 18:44:38 +01003708 Label if_valueisnotpositive(assembler);
Ben Murdochda12d292016-06-02 14:46:10 +01003709 assembler->Branch(assembler->Float64LessThan(
3710 assembler->Float64Constant(0.0), value_value),
Ben Murdochc5610432016-08-08 18:44:38 +01003711 &return_true, &if_valueisnotpositive);
Ben Murdochda12d292016-06-02 14:46:10 +01003712
3713 assembler->Bind(&if_valueisnotpositive);
3714 assembler->Branch(assembler->Float64LessThan(
3715 value_value, assembler->Float64Constant(0.0)),
Ben Murdochc5610432016-08-08 18:44:38 +01003716 &return_true, &return_false);
Ben Murdochda12d292016-06-02 14:46:10 +01003717 }
3718
3719 assembler->Bind(&if_valueisoddball);
3720 {
3721 // The {value} is an Oddball, and every Oddball knows its boolean value.
3722 Node* value_toboolean =
3723 assembler->LoadObjectField(value, Oddball::kToBooleanOffset);
3724 assembler->Return(value_toboolean);
3725 }
3726
3727 assembler->Bind(&if_valueisother);
3728 {
3729 Node* value_map_bitfield = assembler->Load(
3730 MachineType::Uint8(), value_map,
3731 assembler->IntPtrConstant(Map::kBitFieldOffset - kHeapObjectTag));
3732 Node* value_map_undetectable = assembler->Word32And(
3733 value_map_bitfield,
3734 assembler->Int32Constant(1 << Map::kIsUndetectable));
3735
3736 // Check if the {value} is undetectable.
Ben Murdochda12d292016-06-02 14:46:10 +01003737 assembler->Branch(assembler->Word32Equal(value_map_undetectable,
3738 assembler->Int32Constant(0)),
Ben Murdochc5610432016-08-08 18:44:38 +01003739 &return_true, &return_false);
Ben Murdochda12d292016-06-02 14:46:10 +01003740 }
3741 }
Ben Murdochc5610432016-08-08 18:44:38 +01003742 assembler->Bind(&return_false);
3743 assembler->Return(assembler->BooleanConstant(false));
3744
3745 assembler->Bind(&return_true);
3746 assembler->Return(assembler->BooleanConstant(true));
Ben Murdochda12d292016-06-02 14:46:10 +01003747}
3748
Ben Murdochc5610432016-08-08 18:44:38 +01003749void ToIntegerStub::GenerateAssembly(CodeStubAssembler* assembler) const {
3750 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01003751 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +01003752 typedef CodeStubAssembler::Variable Variable;
Ben Murdochda12d292016-06-02 14:46:10 +01003753
3754 Node* context = assembler->Parameter(1);
3755
3756 // We might need to loop once for ToNumber conversion.
3757 Variable var_arg(assembler, MachineRepresentation::kTagged);
3758 Label loop(assembler, &var_arg);
3759 var_arg.Bind(assembler->Parameter(0));
3760 assembler->Goto(&loop);
3761 assembler->Bind(&loop);
3762 {
3763 // Shared entry points.
3764 Label return_arg(assembler), return_zero(assembler, Label::kDeferred);
3765
3766 // Load the current {arg} value.
3767 Node* arg = var_arg.value();
3768
3769 // Check if {arg} is a Smi.
3770 assembler->GotoIf(assembler->WordIsSmi(arg), &return_arg);
3771
3772 // Check if {arg} is a HeapNumber.
3773 Label if_argisheapnumber(assembler),
3774 if_argisnotheapnumber(assembler, Label::kDeferred);
3775 assembler->Branch(assembler->WordEqual(assembler->LoadMap(arg),
3776 assembler->HeapNumberMapConstant()),
3777 &if_argisheapnumber, &if_argisnotheapnumber);
3778
3779 assembler->Bind(&if_argisheapnumber);
3780 {
3781 // Load the floating-point value of {arg}.
3782 Node* arg_value = assembler->LoadHeapNumberValue(arg);
3783
3784 // Check if {arg} is NaN.
3785 assembler->GotoUnless(assembler->Float64Equal(arg_value, arg_value),
3786 &return_zero);
3787
3788 // Truncate {arg} towards zero.
3789 Node* value = assembler->Float64Trunc(arg_value);
3790 var_arg.Bind(assembler->ChangeFloat64ToTagged(value));
3791 assembler->Goto(&return_arg);
3792 }
3793
3794 assembler->Bind(&if_argisnotheapnumber);
3795 {
3796 // Need to convert {arg} to a Number first.
3797 Callable callable = CodeFactory::NonNumberToNumber(assembler->isolate());
3798 var_arg.Bind(assembler->CallStub(callable, context, arg));
3799 assembler->Goto(&loop);
3800 }
3801
3802 assembler->Bind(&return_arg);
3803 assembler->Return(var_arg.value());
3804
3805 assembler->Bind(&return_zero);
3806 assembler->Return(assembler->SmiConstant(Smi::FromInt(0)));
3807 }
3808}
3809
3810void StoreInterceptorStub::GenerateAssembly(
Ben Murdochc5610432016-08-08 18:44:38 +01003811 CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003812 typedef compiler::Node Node;
3813 Node* receiver = assembler->Parameter(0);
3814 Node* name = assembler->Parameter(1);
3815 Node* value = assembler->Parameter(2);
3816 Node* context = assembler->Parameter(3);
3817 assembler->TailCallRuntime(Runtime::kStorePropertyWithInterceptor, context,
3818 receiver, name, value);
3819}
3820
3821void LoadIndexedInterceptorStub::GenerateAssembly(
Ben Murdochc5610432016-08-08 18:44:38 +01003822 CodeStubAssembler* assembler) const {
Ben Murdochda12d292016-06-02 14:46:10 +01003823 typedef compiler::Node Node;
Ben Murdochc5610432016-08-08 18:44:38 +01003824 typedef CodeStubAssembler::Label Label;
Ben Murdochda12d292016-06-02 14:46:10 +01003825 Node* receiver = assembler->Parameter(0);
3826 Node* key = assembler->Parameter(1);
3827 Node* slot = assembler->Parameter(2);
3828 Node* vector = assembler->Parameter(3);
3829 Node* context = assembler->Parameter(4);
3830
3831 Label if_keyispositivesmi(assembler), if_keyisinvalid(assembler);
3832 assembler->Branch(assembler->WordIsPositiveSmi(key), &if_keyispositivesmi,
3833 &if_keyisinvalid);
3834 assembler->Bind(&if_keyispositivesmi);
3835 assembler->TailCallRuntime(Runtime::kLoadElementWithInterceptor, context,
3836 receiver, key);
3837
3838 assembler->Bind(&if_keyisinvalid);
3839 assembler->TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key,
3840 slot, vector);
3841}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003842
Ben Murdochc5610432016-08-08 18:44:38 +01003843// static
3844bool FastCloneShallowObjectStub::IsSupported(ObjectLiteral* expr) {
3845 // FastCloneShallowObjectStub doesn't copy elements, and object literals don't
3846 // support copy-on-write (COW) elements for now.
3847 // TODO(mvstanton): make object literals support COW elements.
3848 return expr->fast_elements() && expr->has_shallow_properties() &&
3849 expr->properties_count() <= kMaximumClonedProperties;
3850}
3851
3852// static
3853int FastCloneShallowObjectStub::PropertiesCount(int literal_length) {
3854 // This heuristic of setting empty literals to have
3855 // kInitialGlobalObjectUnusedPropertiesCount must remain in-sync with the
3856 // runtime.
3857 // TODO(verwaest): Unify this with the heuristic in the runtime.
3858 return literal_length == 0
3859 ? JSObject::kInitialGlobalObjectUnusedPropertiesCount
3860 : literal_length;
3861}
3862
3863// static
3864compiler::Node* FastCloneShallowObjectStub::GenerateFastPath(
3865 CodeStubAssembler* assembler, compiler::CodeAssembler::Label* call_runtime,
3866 compiler::Node* closure, compiler::Node* literals_index,
3867 compiler::Node* properties_count) {
3868 typedef compiler::Node Node;
3869 typedef compiler::CodeAssembler::Label Label;
3870 typedef compiler::CodeAssembler::Variable Variable;
3871
3872 Node* undefined = assembler->UndefinedConstant();
3873 Node* literals_array =
3874 assembler->LoadObjectField(closure, JSFunction::kLiteralsOffset);
3875 Node* allocation_site = assembler->LoadFixedArrayElement(
3876 literals_array, literals_index,
3877 LiteralsArray::kFirstLiteralIndex * kPointerSize,
3878 CodeStubAssembler::SMI_PARAMETERS);
3879 assembler->GotoIf(assembler->WordEqual(allocation_site, undefined),
3880 call_runtime);
3881
3882 // Calculate the object and allocation size based on the properties count.
3883 Node* object_size = assembler->IntPtrAdd(
3884 assembler->WordShl(properties_count, kPointerSizeLog2),
3885 assembler->IntPtrConstant(JSObject::kHeaderSize));
3886 Node* allocation_size = object_size;
3887 if (FLAG_allocation_site_pretenuring) {
3888 allocation_size = assembler->IntPtrAdd(
3889 object_size, assembler->IntPtrConstant(AllocationMemento::kSize));
3890 }
3891 Node* boilerplate = assembler->LoadObjectField(
3892 allocation_site, AllocationSite::kTransitionInfoOffset);
3893 Node* boilerplate_map = assembler->LoadMap(boilerplate);
3894 Node* instance_size = assembler->LoadMapInstanceSize(boilerplate_map);
3895 Node* size_in_words = assembler->WordShr(object_size, kPointerSizeLog2);
3896 assembler->GotoUnless(assembler->Word32Equal(instance_size, size_in_words),
3897 call_runtime);
3898
3899 Node* copy = assembler->Allocate(allocation_size);
3900
3901 // Copy boilerplate elements.
3902 Variable offset(assembler, MachineType::PointerRepresentation());
3903 offset.Bind(assembler->IntPtrConstant(-kHeapObjectTag));
3904 Node* end_offset = assembler->IntPtrAdd(object_size, offset.value());
3905 Label loop_body(assembler, &offset), loop_check(assembler, &offset);
3906 // We should always have an object size greater than zero.
3907 assembler->Goto(&loop_body);
3908 assembler->Bind(&loop_body);
3909 {
3910 // The Allocate above guarantees that the copy lies in new space. This
3911 // allows us to skip write barriers. This is necessary since we may also be
3912 // copying unboxed doubles.
3913 Node* field =
3914 assembler->Load(MachineType::IntPtr(), boilerplate, offset.value());
3915 assembler->StoreNoWriteBarrier(MachineType::PointerRepresentation(), copy,
3916 offset.value(), field);
3917 assembler->Goto(&loop_check);
3918 }
3919 assembler->Bind(&loop_check);
3920 {
3921 offset.Bind(assembler->IntPtrAdd(offset.value(),
3922 assembler->IntPtrConstant(kPointerSize)));
3923 assembler->GotoUnless(
3924 assembler->IntPtrGreaterThanOrEqual(offset.value(), end_offset),
3925 &loop_body);
3926 }
3927
3928 if (FLAG_allocation_site_pretenuring) {
3929 Node* memento = assembler->InnerAllocate(copy, object_size);
3930 assembler->StoreObjectFieldNoWriteBarrier(
3931 memento, HeapObject::kMapOffset,
3932 assembler->LoadRoot(Heap::kAllocationMementoMapRootIndex));
3933 assembler->StoreObjectFieldNoWriteBarrier(
3934 memento, AllocationMemento::kAllocationSiteOffset, allocation_site);
3935 Node* memento_create_count = assembler->LoadObjectField(
3936 allocation_site, AllocationSite::kPretenureCreateCountOffset);
3937 memento_create_count = assembler->SmiAdd(
3938 memento_create_count, assembler->SmiConstant(Smi::FromInt(1)));
3939 assembler->StoreObjectFieldNoWriteBarrier(
3940 allocation_site, AllocationSite::kPretenureCreateCountOffset,
3941 memento_create_count);
3942 }
3943
3944 // TODO(verwaest): Allocate and fill in double boxes.
3945 return copy;
3946}
3947
3948void FastCloneShallowObjectStub::GenerateAssembly(
3949 CodeStubAssembler* assembler) const {
3950 typedef CodeStubAssembler::Label Label;
3951 typedef compiler::Node Node;
3952 Label call_runtime(assembler);
3953 Node* closure = assembler->Parameter(0);
3954 Node* literals_index = assembler->Parameter(1);
3955
3956 Node* properties_count =
3957 assembler->IntPtrConstant(PropertiesCount(this->length()));
3958 Node* copy = GenerateFastPath(assembler, &call_runtime, closure,
3959 literals_index, properties_count);
3960 assembler->Return(copy);
3961
3962 assembler->Bind(&call_runtime);
3963 Node* constant_properties = assembler->Parameter(2);
3964 Node* flags = assembler->Parameter(3);
3965 Node* context = assembler->Parameter(4);
3966 assembler->TailCallRuntime(Runtime::kCreateObjectLiteral, context, closure,
3967 literals_index, constant_properties, flags);
3968}
3969
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003970template<class StateType>
3971void HydrogenCodeStub::TraceTransition(StateType from, StateType to) {
3972 // Note: Although a no-op transition is semantically OK, it is hinting at a
3973 // bug somewhere in our state transition machinery.
3974 DCHECK(from != to);
3975 if (!FLAG_trace_ic) return;
3976 OFStream os(stdout);
3977 os << "[";
3978 PrintBaseName(os);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003979 os << ": " << from << "=>" << to << "]" << std::endl;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003980}
3981
3982
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003983// TODO(svenpanne) Make this a real infix_ostream_iterator.
3984class SimpleListPrinter {
3985 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003986 explicit SimpleListPrinter(std::ostream& os) : os_(os), first_(true) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003987
3988 void Add(const char* s) {
3989 if (first_) {
3990 first_ = false;
3991 } else {
3992 os_ << ",";
3993 }
3994 os_ << s;
Ben Murdoch086aeea2011-05-13 15:57:08 +01003995 }
3996
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003997 private:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003998 std::ostream& os_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003999 bool first_;
4000};
4001
4002
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004003void CallICStub::PrintState(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004004 os << state();
4005}
4006
4007
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004008void JSEntryStub::FinishCode(Handle<Code> code) {
4009 Handle<FixedArray> handler_table =
4010 code->GetIsolate()->factory()->NewFixedArray(1, TENURED);
4011 handler_table->set(0, Smi::FromInt(handler_offset_));
4012 code->set_handler_table(*handler_table);
4013}
4014
4015
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004016void LoadDictionaryElementStub::InitializeDescriptor(
4017 CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004018 descriptor->Initialize(
4019 FUNCTION_ADDR(Runtime_KeyedLoadIC_MissFromStubFailure));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004020}
4021
4022
4023void KeyedLoadGenericStub::InitializeDescriptor(
4024 CodeStubDescriptor* descriptor) {
4025 descriptor->Initialize(
Ben Murdoch097c5b22016-05-18 11:27:45 +01004026 Runtime::FunctionForId(Runtime::kKeyedGetProperty)->entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004027}
4028
4029
4030void HandlerStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
4031 if (kind() == Code::STORE_IC) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004032 descriptor->Initialize(FUNCTION_ADDR(Runtime_StoreIC_MissFromStubFailure));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004033 } else if (kind() == Code::KEYED_LOAD_IC) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004034 descriptor->Initialize(
4035 FUNCTION_ADDR(Runtime_KeyedLoadIC_MissFromStubFailure));
4036 } else if (kind() == Code::KEYED_STORE_IC) {
4037 descriptor->Initialize(
4038 FUNCTION_ADDR(Runtime_KeyedStoreIC_MissFromStubFailure));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004039 }
4040}
4041
4042
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004043CallInterfaceDescriptor HandlerStub::GetCallInterfaceDescriptor() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004044 if (kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004045 return LoadWithVectorDescriptor(isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004046 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004047 DCHECK(kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC);
4048 return VectorStoreICDescriptor(isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004049 }
4050}
4051
4052
4053void StoreFastElementStub::InitializeDescriptor(
4054 CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004055 descriptor->Initialize(
4056 FUNCTION_ADDR(Runtime_KeyedStoreIC_MissFromStubFailure));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004057}
4058
4059
4060void ElementsTransitionAndStoreStub::InitializeDescriptor(
4061 CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004062 descriptor->Initialize(
4063 FUNCTION_ADDR(Runtime_ElementsTransitionAndStoreIC_Miss));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004064}
4065
4066
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004067void ToObjectStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
4068 descriptor->Initialize(Runtime::FunctionForId(Runtime::kToObject)->entry);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004069}
4070
4071
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004072CallInterfaceDescriptor StoreTransitionStub::GetCallInterfaceDescriptor()
4073 const {
4074 return VectorStoreTransitionDescriptor(isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004075}
4076
4077
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004078CallInterfaceDescriptor
4079ElementsTransitionAndStoreStub::GetCallInterfaceDescriptor() const {
4080 return VectorStoreTransitionDescriptor(isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004081}
4082
Ben Murdochc5610432016-08-08 18:44:38 +01004083void FastNewClosureStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004084
4085void FastNewContextStub::InitializeDescriptor(CodeStubDescriptor* d) {}
4086
4087
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004088void TypeofStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {}
4089
4090
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004091void NumberToStringStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004092 descriptor->Initialize(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004093 Runtime::FunctionForId(Runtime::kNumberToString)->entry);
4094}
4095
4096
4097void FastCloneRegExpStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
4098 FastCloneRegExpDescriptor call_descriptor(isolate());
4099 descriptor->Initialize(
4100 Runtime::FunctionForId(Runtime::kCreateRegExpLiteral)->entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004101}
4102
4103
4104void FastCloneShallowArrayStub::InitializeDescriptor(
4105 CodeStubDescriptor* descriptor) {
4106 FastCloneShallowArrayDescriptor call_descriptor(isolate());
4107 descriptor->Initialize(
4108 Runtime::FunctionForId(Runtime::kCreateArrayLiteralStubBailout)->entry);
4109}
4110
4111
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004112void CreateAllocationSiteStub::InitializeDescriptor(CodeStubDescriptor* d) {}
4113
4114
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004115void CreateWeakCellStub::InitializeDescriptor(CodeStubDescriptor* d) {}
4116
4117
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004118void RegExpConstructResultStub::InitializeDescriptor(
4119 CodeStubDescriptor* descriptor) {
4120 descriptor->Initialize(
4121 Runtime::FunctionForId(Runtime::kRegExpConstructResult)->entry);
4122}
4123
4124
4125void TransitionElementsKindStub::InitializeDescriptor(
4126 CodeStubDescriptor* descriptor) {
4127 descriptor->Initialize(
4128 Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry);
4129}
4130
4131
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004132void AllocateHeapNumberStub::InitializeDescriptor(
4133 CodeStubDescriptor* descriptor) {
4134 descriptor->Initialize(
4135 Runtime::FunctionForId(Runtime::kAllocateHeapNumber)->entry);
4136}
4137
4138
Ben Murdochda12d292016-06-02 14:46:10 +01004139#define SIMD128_INIT_DESC(TYPE, Type, type, lane_count, lane_type) \
4140 void Allocate##Type##Stub::InitializeDescriptor( \
4141 CodeStubDescriptor* descriptor) { \
4142 descriptor->Initialize( \
4143 Runtime::FunctionForId(Runtime::kCreate##Type)->entry); \
4144 }
4145SIMD128_TYPES(SIMD128_INIT_DESC)
4146#undef SIMD128_INIT_DESC
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004147
Ben Murdochda12d292016-06-02 14:46:10 +01004148void ToBooleanICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004149 descriptor->Initialize(FUNCTION_ADDR(Runtime_ToBooleanIC_Miss));
4150 descriptor->SetMissHandler(ExternalReference(
4151 Runtime::FunctionForId(Runtime::kToBooleanIC_Miss), isolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004152}
4153
4154
4155void BinaryOpICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004156 descriptor->Initialize(FUNCTION_ADDR(Runtime_BinaryOpIC_Miss));
4157 descriptor->SetMissHandler(ExternalReference(
4158 Runtime::FunctionForId(Runtime::kBinaryOpIC_Miss), isolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004159}
4160
4161
4162void BinaryOpWithAllocationSiteStub::InitializeDescriptor(
4163 CodeStubDescriptor* descriptor) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004164 descriptor->Initialize(
4165 FUNCTION_ADDR(Runtime_BinaryOpIC_MissWithAllocationSite));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004166}
4167
4168
4169void StringAddStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
4170 descriptor->Initialize(Runtime::FunctionForId(Runtime::kStringAdd)->entry);
4171}
4172
4173
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004174void GrowArrayElementsStub::InitializeDescriptor(
4175 CodeStubDescriptor* descriptor) {
4176 descriptor->Initialize(
4177 Runtime::FunctionForId(Runtime::kGrowArrayElements)->entry);
4178}
4179
4180
4181void TypeofStub::GenerateAheadOfTime(Isolate* isolate) {
4182 TypeofStub stub(isolate);
4183 stub.GetCode();
4184}
4185
Ben Murdochc5610432016-08-08 18:44:38 +01004186void HasPropertyStub::GenerateAssembly(CodeStubAssembler* assembler) const {
4187 typedef compiler::Node Node;
4188 typedef CodeStubAssembler::Label Label;
4189 typedef CodeStubAssembler::Variable Variable;
4190
4191 Node* key = assembler->Parameter(0);
4192 Node* object = assembler->Parameter(1);
4193 Node* context = assembler->Parameter(2);
4194
4195 Label call_runtime(assembler), return_true(assembler),
4196 return_false(assembler);
4197
4198 // Ensure object is JSReceiver, otherwise call runtime to throw error.
4199 Label if_objectisnotsmi(assembler);
4200 assembler->Branch(assembler->WordIsSmi(object), &call_runtime,
4201 &if_objectisnotsmi);
4202 assembler->Bind(&if_objectisnotsmi);
4203
4204 Node* map = assembler->LoadMap(object);
4205 Node* instance_type = assembler->LoadMapInstanceType(map);
4206 {
4207 Label if_objectisreceiver(assembler);
4208 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
4209 assembler->Branch(
4210 assembler->Int32GreaterThanOrEqual(
4211 instance_type, assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE)),
4212 &if_objectisreceiver, &call_runtime);
4213 assembler->Bind(&if_objectisreceiver);
4214 }
4215
4216 Variable var_index(assembler, MachineRepresentation::kWord32);
4217
4218 Label keyisindex(assembler), if_iskeyunique(assembler);
4219 assembler->TryToName(key, &keyisindex, &var_index, &if_iskeyunique,
4220 &call_runtime);
4221
4222 assembler->Bind(&if_iskeyunique);
4223 {
4224 Variable var_object(assembler, MachineRepresentation::kTagged);
4225 Variable var_map(assembler, MachineRepresentation::kTagged);
4226 Variable var_instance_type(assembler, MachineRepresentation::kWord8);
4227
4228 Variable* merged_variables[] = {&var_object, &var_map, &var_instance_type};
4229 Label loop(assembler, arraysize(merged_variables), merged_variables);
4230 var_object.Bind(object);
4231 var_map.Bind(map);
4232 var_instance_type.Bind(instance_type);
4233 assembler->Goto(&loop);
4234 assembler->Bind(&loop);
4235 {
4236 Label next_proto(assembler);
4237 assembler->TryLookupProperty(var_object.value(), var_map.value(),
4238 var_instance_type.value(), key, &return_true,
4239 &next_proto, &call_runtime);
4240 assembler->Bind(&next_proto);
4241
4242 Node* proto = assembler->LoadMapPrototype(var_map.value());
4243
4244 Label if_not_null(assembler);
4245 assembler->Branch(assembler->WordEqual(proto, assembler->NullConstant()),
4246 &return_false, &if_not_null);
4247 assembler->Bind(&if_not_null);
4248
4249 Node* map = assembler->LoadMap(proto);
4250 Node* instance_type = assembler->LoadMapInstanceType(map);
4251
4252 var_object.Bind(proto);
4253 var_map.Bind(map);
4254 var_instance_type.Bind(instance_type);
4255 assembler->Goto(&loop);
4256 }
4257 }
4258 assembler->Bind(&keyisindex);
4259 {
4260 Variable var_object(assembler, MachineRepresentation::kTagged);
4261 Variable var_map(assembler, MachineRepresentation::kTagged);
4262 Variable var_instance_type(assembler, MachineRepresentation::kWord8);
4263
4264 Variable* merged_variables[] = {&var_object, &var_map, &var_instance_type};
4265 Label loop(assembler, arraysize(merged_variables), merged_variables);
4266 var_object.Bind(object);
4267 var_map.Bind(map);
4268 var_instance_type.Bind(instance_type);
4269 assembler->Goto(&loop);
4270 assembler->Bind(&loop);
4271 {
4272 Label next_proto(assembler);
4273 assembler->TryLookupElement(var_object.value(), var_map.value(),
4274 var_instance_type.value(), var_index.value(),
4275 &return_true, &next_proto, &call_runtime);
4276 assembler->Bind(&next_proto);
4277
4278 Node* proto = assembler->LoadMapPrototype(var_map.value());
4279
4280 Label if_not_null(assembler);
4281 assembler->Branch(assembler->WordEqual(proto, assembler->NullConstant()),
4282 &return_false, &if_not_null);
4283 assembler->Bind(&if_not_null);
4284
4285 Node* map = assembler->LoadMap(proto);
4286 Node* instance_type = assembler->LoadMapInstanceType(map);
4287
4288 var_object.Bind(proto);
4289 var_map.Bind(map);
4290 var_instance_type.Bind(instance_type);
4291 assembler->Goto(&loop);
4292 }
4293 }
4294 assembler->Bind(&return_true);
4295 assembler->Return(assembler->BooleanConstant(true));
4296
4297 assembler->Bind(&return_false);
4298 assembler->Return(assembler->BooleanConstant(false));
4299
4300 assembler->Bind(&call_runtime);
4301 assembler->TailCallRuntime(Runtime::kHasProperty, context, key, object);
4302}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004303
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004304void CreateAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
4305 CreateAllocationSiteStub stub(isolate);
4306 stub.GetCode();
4307}
4308
4309
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004310void CreateWeakCellStub::GenerateAheadOfTime(Isolate* isolate) {
4311 CreateWeakCellStub stub(isolate);
4312 stub.GetCode();
4313}
4314
4315
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004316void StoreElementStub::Generate(MacroAssembler* masm) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004317 DCHECK_EQ(DICTIONARY_ELEMENTS, elements_kind());
4318 ElementHandlerCompiler::GenerateStoreSlow(masm);
Ben Murdoch257744e2011-11-30 15:57:28 +00004319}
4320
4321
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004322// static
4323void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) {
4324 StoreFastElementStub(isolate, false, FAST_HOLEY_ELEMENTS, STANDARD_STORE)
4325 .GetCode();
4326 StoreFastElementStub(isolate, false, FAST_HOLEY_ELEMENTS,
4327 STORE_AND_GROW_NO_TRANSITION).GetCode();
4328 for (int i = FIRST_FAST_ELEMENTS_KIND; i <= LAST_FAST_ELEMENTS_KIND; i++) {
4329 ElementsKind kind = static_cast<ElementsKind>(i);
4330 StoreFastElementStub(isolate, true, kind, STANDARD_STORE).GetCode();
4331 StoreFastElementStub(isolate, true, kind, STORE_AND_GROW_NO_TRANSITION)
4332 .GetCode();
4333 }
4334}
4335
4336
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004337void ArrayConstructorStub::PrintName(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004338 os << "ArrayConstructorStub";
4339 switch (argument_count()) {
4340 case ANY:
4341 os << "_Any";
4342 break;
4343 case NONE:
4344 os << "_None";
4345 break;
4346 case ONE:
4347 os << "_One";
4348 break;
4349 case MORE_THAN_ONE:
4350 os << "_More_Than_One";
4351 break;
4352 }
4353 return;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004354}
4355
4356
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004357std::ostream& ArrayConstructorStubBase::BasePrintName(
4358 std::ostream& os, // NOLINT
4359 const char* name) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004360 os << name << "_" << ElementsKindToString(elements_kind());
4361 if (override_mode() == DISABLE_ALLOCATION_SITES) {
4362 os << "_DISABLE_ALLOCATION_SITES";
4363 }
4364 return os;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004365}
4366
Ben Murdochda12d292016-06-02 14:46:10 +01004367bool ToBooleanICStub::UpdateStatus(Handle<Object> object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004368 Types new_types = types();
4369 Types old_types = new_types;
4370 bool to_boolean_value = new_types.UpdateStatus(object);
4371 TraceTransition(old_types, new_types);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004372 set_sub_minor_key(TypesBits::update(sub_minor_key(), new_types.ToIntegral()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004373 return to_boolean_value;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004374}
4375
Ben Murdochda12d292016-06-02 14:46:10 +01004376void ToBooleanICStub::PrintState(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004377 os << types();
4378}
4379
Ben Murdochda12d292016-06-02 14:46:10 +01004380std::ostream& operator<<(std::ostream& os, const ToBooleanICStub::Types& s) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004381 os << "(";
4382 SimpleListPrinter p(os);
4383 if (s.IsEmpty()) p.Add("None");
Ben Murdochda12d292016-06-02 14:46:10 +01004384 if (s.Contains(ToBooleanICStub::UNDEFINED)) p.Add("Undefined");
4385 if (s.Contains(ToBooleanICStub::BOOLEAN)) p.Add("Bool");
4386 if (s.Contains(ToBooleanICStub::NULL_TYPE)) p.Add("Null");
4387 if (s.Contains(ToBooleanICStub::SMI)) p.Add("Smi");
4388 if (s.Contains(ToBooleanICStub::SPEC_OBJECT)) p.Add("SpecObject");
4389 if (s.Contains(ToBooleanICStub::STRING)) p.Add("String");
4390 if (s.Contains(ToBooleanICStub::SYMBOL)) p.Add("Symbol");
4391 if (s.Contains(ToBooleanICStub::HEAP_NUMBER)) p.Add("HeapNumber");
4392 if (s.Contains(ToBooleanICStub::SIMD_VALUE)) p.Add("SimdValue");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004393 return os << ")";
4394}
4395
Ben Murdochda12d292016-06-02 14:46:10 +01004396bool ToBooleanICStub::Types::UpdateStatus(Handle<Object> object) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004397 if (object->IsUndefined()) {
4398 Add(UNDEFINED);
4399 return false;
4400 } else if (object->IsBoolean()) {
4401 Add(BOOLEAN);
4402 return object->IsTrue();
4403 } else if (object->IsNull()) {
4404 Add(NULL_TYPE);
4405 return false;
4406 } else if (object->IsSmi()) {
4407 Add(SMI);
4408 return Smi::cast(*object)->value() != 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004409 } else if (object->IsJSReceiver()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004410 Add(SPEC_OBJECT);
Ben Murdochda12d292016-06-02 14:46:10 +01004411 return !object->IsUndetectable();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004412 } else if (object->IsString()) {
Ben Murdochda12d292016-06-02 14:46:10 +01004413 DCHECK(!object->IsUndetectable());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004414 Add(STRING);
Ben Murdoch097c5b22016-05-18 11:27:45 +01004415 return String::cast(*object)->length() != 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004416 } else if (object->IsSymbol()) {
4417 Add(SYMBOL);
4418 return true;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004419 } else if (object->IsHeapNumber()) {
Ben Murdochda12d292016-06-02 14:46:10 +01004420 DCHECK(!object->IsUndetectable());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004421 Add(HEAP_NUMBER);
4422 double value = HeapNumber::cast(*object)->value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004423 return value != 0 && !std::isnan(value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004424 } else if (object->IsSimd128Value()) {
4425 Add(SIMD_VALUE);
4426 return true;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004427 } else {
4428 // We should never see an internal object at runtime here!
4429 UNREACHABLE();
4430 return true;
4431 }
4432}
4433
Ben Murdochda12d292016-06-02 14:46:10 +01004434bool ToBooleanICStub::Types::NeedsMap() const {
4435 return Contains(ToBooleanICStub::SPEC_OBJECT) ||
4436 Contains(ToBooleanICStub::STRING) ||
4437 Contains(ToBooleanICStub::SYMBOL) ||
4438 Contains(ToBooleanICStub::HEAP_NUMBER) ||
4439 Contains(ToBooleanICStub::SIMD_VALUE);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004440}
4441
4442
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004443void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) {
4444 StubFailureTrampolineStub stub1(isolate, NOT_JS_FUNCTION_STUB_MODE);
4445 StubFailureTrampolineStub stub2(isolate, JS_FUNCTION_STUB_MODE);
4446 stub1.GetCode();
4447 stub2.GetCode();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004448}
4449
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004450
4451void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function,
4452 intptr_t stack_pointer,
4453 Isolate* isolate) {
4454 FunctionEntryHook entry_hook = isolate->function_entry_hook();
4455 DCHECK(entry_hook != NULL);
4456 entry_hook(function, stack_pointer);
4457}
4458
Ben Murdochc5610432016-08-08 18:44:38 +01004459void ArrayNoArgumentConstructorStub::GenerateAssembly(
4460 CodeStubAssembler* assembler) const {
4461 typedef compiler::Node Node;
4462 Node* native_context = assembler->LoadObjectField(
4463 assembler->Parameter(
4464 ArrayNoArgumentConstructorDescriptor::kFunctionIndex),
4465 JSFunction::kContextOffset);
4466 bool track_allocation_site =
4467 AllocationSite::GetMode(elements_kind()) == TRACK_ALLOCATION_SITE &&
4468 override_mode() != DISABLE_ALLOCATION_SITES;
4469 Node* allocation_site =
4470 track_allocation_site
4471 ? assembler->Parameter(
4472 ArrayNoArgumentConstructorDescriptor::kAllocationSiteIndex)
4473 : nullptr;
4474 Node* array_map =
4475 assembler->LoadJSArrayElementsMap(elements_kind(), native_context);
4476 Node* array = assembler->AllocateJSArray(
4477 elements_kind(), array_map,
4478 assembler->IntPtrConstant(JSArray::kPreallocatedArrayElements),
4479 assembler->IntPtrConstant(0), allocation_site);
4480 assembler->Return(array);
4481}
4482
4483void InternalArrayNoArgumentConstructorStub::GenerateAssembly(
4484 CodeStubAssembler* assembler) const {
4485 typedef compiler::Node Node;
4486 Node* array_map = assembler->LoadObjectField(
4487 assembler->Parameter(
4488 ArrayNoArgumentConstructorDescriptor::kFunctionIndex),
4489 JSFunction::kPrototypeOrInitialMapOffset);
4490 Node* array = assembler->AllocateJSArray(
4491 elements_kind(), array_map,
4492 assembler->IntPtrConstant(JSArray::kPreallocatedArrayElements),
4493 assembler->IntPtrConstant(0), nullptr);
4494 assembler->Return(array);
4495}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004496
4497ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate)
4498 : PlatformCodeStub(isolate) {
4499 minor_key_ = ArgumentCountBits::encode(ANY);
4500 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
4501}
4502
4503
4504ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate,
4505 int argument_count)
4506 : PlatformCodeStub(isolate) {
4507 if (argument_count == 0) {
4508 minor_key_ = ArgumentCountBits::encode(NONE);
4509 } else if (argument_count == 1) {
4510 minor_key_ = ArgumentCountBits::encode(ONE);
4511 } else if (argument_count >= 2) {
4512 minor_key_ = ArgumentCountBits::encode(MORE_THAN_ONE);
4513 } else {
4514 UNREACHABLE();
4515 }
4516 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
4517}
4518
4519
4520InternalArrayConstructorStub::InternalArrayConstructorStub(
4521 Isolate* isolate) : PlatformCodeStub(isolate) {
4522 InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
4523}
4524
4525
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004526Representation RepresentationFromType(Type* type) {
4527 if (type->Is(Type::UntaggedIntegral())) {
4528 return Representation::Integer32();
4529 }
4530
4531 if (type->Is(Type::TaggedSigned())) {
4532 return Representation::Smi();
4533 }
4534
4535 if (type->Is(Type::UntaggedPointer())) {
4536 return Representation::External();
4537 }
4538
4539 DCHECK(!type->Is(Type::Untagged()));
4540 return Representation::Tagged();
4541}
4542
4543} // namespace internal
4544} // namespace v8