• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "v8.h"
29 
30 #include "bootstrapper.h"
31 #include "code-stubs.h"
32 #include "stub-cache.h"
33 #include "factory.h"
34 #include "gdb-jit.h"
35 #include "macro-assembler.h"
36 
37 namespace v8 {
38 namespace internal {
39 
FindCodeInCache(Code ** code_out)40 bool CodeStub::FindCodeInCache(Code** code_out) {
41   Heap* heap = Isolate::Current()->heap();
42   int index = heap->code_stubs()->FindEntry(GetKey());
43   if (index != UnseededNumberDictionary::kNotFound) {
44     *code_out = Code::cast(heap->code_stubs()->ValueAt(index));
45     return true;
46   }
47   return false;
48 }
49 
50 
GenerateCode(MacroAssembler * masm)51 void CodeStub::GenerateCode(MacroAssembler* masm) {
52   // Update the static counter each time a new code stub is generated.
53   masm->isolate()->counters()->code_stubs()->Increment();
54 
55   // Nested stubs are not allowed for leaves.
56   AllowStubCallsScope allow_scope(masm, false);
57 
58   // Generate the code for the stub.
59   masm->set_generating_stub(true);
60   NoCurrentFrameScope scope(masm);
61   Generate(masm);
62 }
63 
64 
GetName()65 SmartArrayPointer<const char> CodeStub::GetName() {
66   char buffer[100];
67   NoAllocationStringAllocator allocator(buffer,
68                                         static_cast<unsigned>(sizeof(buffer)));
69   StringStream stream(&allocator);
70   PrintName(&stream);
71   return stream.ToCString();
72 }
73 
74 
RecordCodeGeneration(Code * code,MacroAssembler * masm)75 void CodeStub::RecordCodeGeneration(Code* code, MacroAssembler* masm) {
76   code->set_major_key(MajorKey());
77 
78   Isolate* isolate = masm->isolate();
79   SmartArrayPointer<const char> name = GetName();
80   PROFILE(isolate, CodeCreateEvent(Logger::STUB_TAG, code, *name));
81   GDBJIT(AddCode(GDBJITInterface::STUB, *name, code));
82   Counters* counters = isolate->counters();
83   counters->total_stubs_code_size()->Increment(code->instruction_size());
84 
85 #ifdef ENABLE_DISASSEMBLER
86   if (FLAG_print_code_stubs) {
87     code->Disassemble(*name);
88     PrintF("\n");
89   }
90 #endif
91 }
92 
93 
GetCodeKind()94 int CodeStub::GetCodeKind() {
95   return Code::STUB;
96 }
97 
98 
GetCode()99 Handle<Code> CodeStub::GetCode() {
100   Isolate* isolate = Isolate::Current();
101   Factory* factory = isolate->factory();
102   Heap* heap = isolate->heap();
103   Code* code;
104   if (UseSpecialCache()
105       ? FindCodeInSpecialCache(&code)
106       : FindCodeInCache(&code)) {
107     ASSERT(IsPregenerated() == code->is_pregenerated());
108     return Handle<Code>(code);
109   }
110 
111   {
112     HandleScope scope(isolate);
113 
114     // Generate the new code.
115     MacroAssembler masm(isolate, NULL, 256);
116     GenerateCode(&masm);
117 
118     // Create the code object.
119     CodeDesc desc;
120     masm.GetCode(&desc);
121 
122     // Copy the generated code into a heap object.
123     Code::Flags flags = Code::ComputeFlags(
124         static_cast<Code::Kind>(GetCodeKind()),
125         GetICState());
126     Handle<Code> new_object = factory->NewCode(
127         desc, flags, masm.CodeObject(), NeedsImmovableCode());
128     RecordCodeGeneration(*new_object, &masm);
129     FinishCode(new_object);
130 
131     if (UseSpecialCache()) {
132       AddToSpecialCache(new_object);
133     } else {
134       // Update the dictionary and the root in Heap.
135       Handle<UnseededNumberDictionary> dict =
136           factory->DictionaryAtNumberPut(
137               Handle<UnseededNumberDictionary>(heap->code_stubs()),
138               GetKey(),
139               new_object);
140       heap->public_set_code_stubs(*dict);
141     }
142     code = *new_object;
143   }
144 
145   Activate(code);
146   ASSERT(!NeedsImmovableCode() || heap->lo_space()->Contains(code));
147   return Handle<Code>(code, isolate);
148 }
149 
150 
MajorName(CodeStub::Major major_key,bool allow_unknown_keys)151 const char* CodeStub::MajorName(CodeStub::Major major_key,
152                                 bool allow_unknown_keys) {
153   switch (major_key) {
154 #define DEF_CASE(name) case name: return #name "Stub";
155     CODE_STUB_LIST(DEF_CASE)
156 #undef DEF_CASE
157     default:
158       if (!allow_unknown_keys) {
159         UNREACHABLE();
160       }
161       return NULL;
162   }
163 }
164 
165 
PrintName(StringStream * stream)166 void CodeStub::PrintName(StringStream* stream) {
167   stream->Add("%s", MajorName(MajorKey(), false));
168 }
169 
170 
AddToSpecialCache(Handle<Code> new_object)171 void ICCompareStub::AddToSpecialCache(Handle<Code> new_object) {
172   ASSERT(*known_map_ != NULL);
173   Isolate* isolate = new_object->GetIsolate();
174   Factory* factory = isolate->factory();
175   return Map::UpdateCodeCache(known_map_,
176                               factory->compare_ic_symbol(),
177                               new_object);
178 }
179 
180 
FindCodeInSpecialCache(Code ** code_out)181 bool ICCompareStub::FindCodeInSpecialCache(Code** code_out) {
182   Isolate* isolate = known_map_->GetIsolate();
183   Factory* factory = isolate->factory();
184   Code::Flags flags = Code::ComputeFlags(
185       static_cast<Code::Kind>(GetCodeKind()),
186       UNINITIALIZED);
187   Handle<Object> probe(
188       known_map_->FindInCodeCache(*factory->compare_ic_symbol(), flags));
189   if (probe->IsCode()) {
190     *code_out = Code::cast(*probe);
191     return true;
192   }
193   return false;
194 }
195 
196 
MinorKey()197 int ICCompareStub::MinorKey() {
198   return OpField::encode(op_ - Token::EQ) | StateField::encode(state_);
199 }
200 
201 
Generate(MacroAssembler * masm)202 void ICCompareStub::Generate(MacroAssembler* masm) {
203   switch (state_) {
204     case CompareIC::UNINITIALIZED:
205       GenerateMiss(masm);
206       break;
207     case CompareIC::SMIS:
208       GenerateSmis(masm);
209       break;
210     case CompareIC::HEAP_NUMBERS:
211       GenerateHeapNumbers(masm);
212       break;
213     case CompareIC::STRINGS:
214       GenerateStrings(masm);
215       break;
216     case CompareIC::SYMBOLS:
217       GenerateSymbols(masm);
218       break;
219     case CompareIC::OBJECTS:
220       GenerateObjects(masm);
221       break;
222     case CompareIC::KNOWN_OBJECTS:
223       ASSERT(*known_map_ != NULL);
224       GenerateKnownObjects(masm);
225       break;
226     default:
227       UNREACHABLE();
228   }
229 }
230 
231 
PrintName(StringStream * stream)232 void InstanceofStub::PrintName(StringStream* stream) {
233   const char* args = "";
234   if (HasArgsInRegisters()) {
235     args = "_REGS";
236   }
237 
238   const char* inline_check = "";
239   if (HasCallSiteInlineCheck()) {
240     inline_check = "_INLINE";
241   }
242 
243   const char* return_true_false_object = "";
244   if (ReturnTrueFalseObject()) {
245     return_true_false_object = "_TRUEFALSE";
246   }
247 
248   stream->Add("InstanceofStub%s%s%s",
249               args,
250               inline_check,
251               return_true_false_object);
252 }
253 
254 
FinishCode(Handle<Code> code)255 void JSEntryStub::FinishCode(Handle<Code> code) {
256   Handle<FixedArray> handler_table =
257       code->GetIsolate()->factory()->NewFixedArray(1, TENURED);
258   handler_table->set(0, Smi::FromInt(handler_offset_));
259   code->set_handler_table(*handler_table);
260 }
261 
262 
Generate(MacroAssembler * masm)263 void KeyedLoadElementStub::Generate(MacroAssembler* masm) {
264   switch (elements_kind_) {
265     case FAST_ELEMENTS:
266     case FAST_SMI_ONLY_ELEMENTS:
267       KeyedLoadStubCompiler::GenerateLoadFastElement(masm);
268       break;
269     case FAST_DOUBLE_ELEMENTS:
270       KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(masm);
271       break;
272     case EXTERNAL_BYTE_ELEMENTS:
273     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
274     case EXTERNAL_SHORT_ELEMENTS:
275     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
276     case EXTERNAL_INT_ELEMENTS:
277     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
278     case EXTERNAL_FLOAT_ELEMENTS:
279     case EXTERNAL_DOUBLE_ELEMENTS:
280     case EXTERNAL_PIXEL_ELEMENTS:
281       KeyedLoadStubCompiler::GenerateLoadExternalArray(masm, elements_kind_);
282       break;
283     case DICTIONARY_ELEMENTS:
284       KeyedLoadStubCompiler::GenerateLoadDictionaryElement(masm);
285       break;
286     case NON_STRICT_ARGUMENTS_ELEMENTS:
287       UNREACHABLE();
288       break;
289   }
290 }
291 
292 
Generate(MacroAssembler * masm)293 void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
294   switch (elements_kind_) {
295     case FAST_ELEMENTS:
296     case FAST_SMI_ONLY_ELEMENTS: {
297       KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
298                                                        is_js_array_,
299                                                        elements_kind_,
300                                                        grow_mode_);
301     }
302       break;
303     case FAST_DOUBLE_ELEMENTS:
304       KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
305                                                              is_js_array_,
306                                                              grow_mode_);
307       break;
308     case EXTERNAL_BYTE_ELEMENTS:
309     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
310     case EXTERNAL_SHORT_ELEMENTS:
311     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
312     case EXTERNAL_INT_ELEMENTS:
313     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
314     case EXTERNAL_FLOAT_ELEMENTS:
315     case EXTERNAL_DOUBLE_ELEMENTS:
316     case EXTERNAL_PIXEL_ELEMENTS:
317       KeyedStoreStubCompiler::GenerateStoreExternalArray(masm, elements_kind_);
318       break;
319     case DICTIONARY_ELEMENTS:
320       KeyedStoreStubCompiler::GenerateStoreDictionaryElement(masm);
321       break;
322     case NON_STRICT_ARGUMENTS_ELEMENTS:
323       UNREACHABLE();
324       break;
325   }
326 }
327 
328 
PrintName(StringStream * stream)329 void ArgumentsAccessStub::PrintName(StringStream* stream) {
330   stream->Add("ArgumentsAccessStub_");
331   switch (type_) {
332     case READ_ELEMENT: stream->Add("ReadElement"); break;
333     case NEW_NON_STRICT_FAST: stream->Add("NewNonStrictFast"); break;
334     case NEW_NON_STRICT_SLOW: stream->Add("NewNonStrictSlow"); break;
335     case NEW_STRICT: stream->Add("NewStrict"); break;
336   }
337 }
338 
339 
PrintName(StringStream * stream)340 void CallFunctionStub::PrintName(StringStream* stream) {
341   stream->Add("CallFunctionStub_Args%d", argc_);
342   if (ReceiverMightBeImplicit()) stream->Add("_Implicit");
343   if (RecordCallTarget()) stream->Add("_Recording");
344 }
345 
346 
PrintName(StringStream * stream)347 void CallConstructStub::PrintName(StringStream* stream) {
348   stream->Add("CallConstructStub");
349   if (RecordCallTarget()) stream->Add("_Recording");
350 }
351 
352 
PrintName(StringStream * stream)353 void ToBooleanStub::PrintName(StringStream* stream) {
354   stream->Add("ToBooleanStub_");
355   types_.Print(stream);
356 }
357 
358 
Print(StringStream * stream) const359 void ToBooleanStub::Types::Print(StringStream* stream) const {
360   if (IsEmpty()) stream->Add("None");
361   if (Contains(UNDEFINED)) stream->Add("Undefined");
362   if (Contains(BOOLEAN)) stream->Add("Bool");
363   if (Contains(NULL_TYPE)) stream->Add("Null");
364   if (Contains(SMI)) stream->Add("Smi");
365   if (Contains(SPEC_OBJECT)) stream->Add("SpecObject");
366   if (Contains(STRING)) stream->Add("String");
367   if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber");
368 }
369 
370 
TraceTransition(Types to) const371 void ToBooleanStub::Types::TraceTransition(Types to) const {
372   if (!FLAG_trace_ic) return;
373   char buffer[100];
374   NoAllocationStringAllocator allocator(buffer,
375                                         static_cast<unsigned>(sizeof(buffer)));
376   StringStream stream(&allocator);
377   stream.Add("[ToBooleanIC (");
378   Print(&stream);
379   stream.Add("->");
380   to.Print(&stream);
381   stream.Add(")]\n");
382   stream.OutputToStdOut();
383 }
384 
385 
Record(Handle<Object> object)386 bool ToBooleanStub::Types::Record(Handle<Object> object) {
387   if (object->IsUndefined()) {
388     Add(UNDEFINED);
389     return false;
390   } else if (object->IsBoolean()) {
391     Add(BOOLEAN);
392     return object->IsTrue();
393   } else if (object->IsNull()) {
394     Add(NULL_TYPE);
395     return false;
396   } else if (object->IsSmi()) {
397     Add(SMI);
398     return Smi::cast(*object)->value() != 0;
399   } else if (object->IsSpecObject()) {
400     Add(SPEC_OBJECT);
401     return !object->IsUndetectableObject();
402   } else if (object->IsString()) {
403     Add(STRING);
404     return !object->IsUndetectableObject() &&
405         String::cast(*object)->length() != 0;
406   } else if (object->IsHeapNumber()) {
407     ASSERT(!object->IsUndetectableObject());
408     Add(HEAP_NUMBER);
409     double value = HeapNumber::cast(*object)->value();
410     return value != 0 && !isnan(value);
411   } else {
412     // We should never see an internal object at runtime here!
413     UNREACHABLE();
414     return true;
415   }
416 }
417 
418 
NeedsMap() const419 bool ToBooleanStub::Types::NeedsMap() const {
420   return Contains(ToBooleanStub::SPEC_OBJECT)
421       || Contains(ToBooleanStub::STRING)
422       || Contains(ToBooleanStub::HEAP_NUMBER);
423 }
424 
425 
CanBeUndetectable() const426 bool ToBooleanStub::Types::CanBeUndetectable() const {
427   return Contains(ToBooleanStub::SPEC_OBJECT)
428       || Contains(ToBooleanStub::STRING);
429 }
430 
431 
Generate(MacroAssembler * masm)432 void ElementsTransitionAndStoreStub::Generate(MacroAssembler* masm) {
433   Label fail;
434   if (!FLAG_trace_elements_transitions) {
435     if (to_ == FAST_ELEMENTS) {
436       if (from_ == FAST_SMI_ONLY_ELEMENTS) {
437         ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
438       } else if (from_ == FAST_DOUBLE_ELEMENTS) {
439         ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail);
440       } else {
441         UNREACHABLE();
442       }
443       KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
444                                                        is_jsarray_,
445                                                        FAST_ELEMENTS,
446                                                        grow_mode_);
447     } else if (from_ == FAST_SMI_ONLY_ELEMENTS && to_ == FAST_DOUBLE_ELEMENTS) {
448       ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
449       KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
450                                                              is_jsarray_,
451                                                              grow_mode_);
452     } else {
453       UNREACHABLE();
454     }
455   }
456   masm->bind(&fail);
457   KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode_);
458 }
459 
460 } }  // namespace v8::internal
461