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