[V8] Introduce a QML compilation mode
[profile/ivi/qtjsbackend.git] / src / 3rdparty / v8 / src / code-stubs.cc
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
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
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
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
75 void CodeStub::RecordCodeGeneration(Code* code, MacroAssembler* masm) {
76   Isolate* isolate = masm->isolate();
77   SmartArrayPointer<const char> name = GetName();
78   PROFILE(isolate, CodeCreateEvent(Logger::STUB_TAG, code, *name));
79   GDBJIT(AddCode(GDBJITInterface::STUB, *name, code));
80   Counters* counters = isolate->counters();
81   counters->total_stubs_code_size()->Increment(code->instruction_size());
82 }
83
84
85 int CodeStub::GetCodeKind() {
86   return Code::STUB;
87 }
88
89
90 Handle<Code> CodeStub::GetCode() {
91   Isolate* isolate = Isolate::Current();
92   Factory* factory = isolate->factory();
93   Heap* heap = isolate->heap();
94   Code* code;
95   if (UseSpecialCache()
96       ? FindCodeInSpecialCache(&code)
97       : FindCodeInCache(&code)) {
98     ASSERT(IsPregenerated() == code->is_pregenerated());
99     return Handle<Code>(code);
100   }
101
102   {
103     HandleScope scope(isolate);
104
105     // Generate the new code.
106     MacroAssembler masm(isolate, NULL, 256);
107     GenerateCode(&masm);
108
109     // Create the code object.
110     CodeDesc desc;
111     masm.GetCode(&desc);
112
113     // Copy the generated code into a heap object.
114     Code::Flags flags = Code::ComputeFlags(
115         static_cast<Code::Kind>(GetCodeKind()),
116         GetICState());
117     Handle<Code> new_object = factory->NewCode(
118         desc, flags, masm.CodeObject(), NeedsImmovableCode());
119     new_object->set_major_key(MajorKey());
120     FinishCode(new_object);
121     RecordCodeGeneration(*new_object, &masm);
122
123 #ifdef ENABLE_DISASSEMBLER
124     if (FLAG_print_code_stubs) {
125       new_object->Disassemble(*GetName());
126       PrintF("\n");
127     }
128 #endif
129
130     if (UseSpecialCache()) {
131       AddToSpecialCache(new_object);
132     } else {
133       // Update the dictionary and the root in Heap.
134       Handle<UnseededNumberDictionary> dict =
135           factory->DictionaryAtNumberPut(
136               Handle<UnseededNumberDictionary>(heap->code_stubs()),
137               GetKey(),
138               new_object);
139       heap->public_set_code_stubs(*dict);
140     }
141     code = *new_object;
142   }
143
144   Activate(code);
145   ASSERT(!NeedsImmovableCode() || heap->lo_space()->Contains(code));
146   return Handle<Code>(code, isolate);
147 }
148
149
150 const char* CodeStub::MajorName(CodeStub::Major major_key,
151                                 bool allow_unknown_keys) {
152   switch (major_key) {
153 #define DEF_CASE(name) case name: return #name "Stub";
154     CODE_STUB_LIST(DEF_CASE)
155 #undef DEF_CASE
156     default:
157       if (!allow_unknown_keys) {
158         UNREACHABLE();
159       }
160       return NULL;
161   }
162 }
163
164
165 void CodeStub::PrintName(StringStream* stream) {
166   stream->Add("%s", MajorName(MajorKey(), false));
167 }
168
169
170 void ICCompareStub::AddToSpecialCache(Handle<Code> new_object) {
171   ASSERT(*known_map_ != NULL);
172   Isolate* isolate = new_object->GetIsolate();
173   Factory* factory = isolate->factory();
174   return Map::UpdateCodeCache(known_map_,
175                               factory->compare_ic_symbol(),
176                               new_object);
177 }
178
179
180 bool ICCompareStub::FindCodeInSpecialCache(Code** code_out) {
181   Isolate* isolate = known_map_->GetIsolate();
182   Factory* factory = isolate->factory();
183   Code::Flags flags = Code::ComputeFlags(
184       static_cast<Code::Kind>(GetCodeKind()),
185       UNINITIALIZED);
186   Handle<Object> probe(
187       known_map_->FindInCodeCache(*factory->compare_ic_symbol(), flags));
188   if (probe->IsCode()) {
189     *code_out = Code::cast(*probe);
190     return true;
191   }
192   return false;
193 }
194
195
196 int ICCompareStub::MinorKey() {
197   return OpField::encode(op_ - Token::EQ) | StateField::encode(state_);
198 }
199
200
201 void ICCompareStub::Generate(MacroAssembler* masm) {
202   switch (state_) {
203     case CompareIC::UNINITIALIZED:
204       GenerateMiss(masm);
205       break;
206     case CompareIC::SMIS:
207       GenerateSmis(masm);
208       break;
209     case CompareIC::HEAP_NUMBERS:
210       GenerateHeapNumbers(masm);
211       break;
212     case CompareIC::STRINGS:
213       GenerateStrings(masm);
214       break;
215     case CompareIC::SYMBOLS:
216       GenerateSymbols(masm);
217       break;
218     case CompareIC::OBJECTS:
219       GenerateObjects(masm);
220       break;
221     case CompareIC::KNOWN_OBJECTS:
222       ASSERT(*known_map_ != NULL);
223       GenerateKnownObjects(masm);
224       break;
225     default:
226       UNREACHABLE();
227   }
228 }
229
230
231 void InstanceofStub::PrintName(StringStream* stream) {
232   const char* args = "";
233   if (HasArgsInRegisters()) {
234     args = "_REGS";
235   }
236
237   const char* inline_check = "";
238   if (HasCallSiteInlineCheck()) {
239     inline_check = "_INLINE";
240   }
241
242   const char* return_true_false_object = "";
243   if (ReturnTrueFalseObject()) {
244     return_true_false_object = "_TRUEFALSE";
245   }
246
247   stream->Add("InstanceofStub%s%s%s",
248               args,
249               inline_check,
250               return_true_false_object);
251 }
252
253
254 void JSEntryStub::FinishCode(Handle<Code> code) {
255   Handle<FixedArray> handler_table =
256       code->GetIsolate()->factory()->NewFixedArray(1, TENURED);
257   handler_table->set(0, Smi::FromInt(handler_offset_));
258   code->set_handler_table(*handler_table);
259 }
260
261
262 void KeyedLoadElementStub::Generate(MacroAssembler* masm) {
263   switch (elements_kind_) {
264     case FAST_ELEMENTS:
265     case FAST_SMI_ONLY_ELEMENTS:
266       KeyedLoadStubCompiler::GenerateLoadFastElement(masm);
267       break;
268     case FAST_DOUBLE_ELEMENTS:
269       KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(masm);
270       break;
271     case EXTERNAL_BYTE_ELEMENTS:
272     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
273     case EXTERNAL_SHORT_ELEMENTS:
274     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
275     case EXTERNAL_INT_ELEMENTS:
276     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
277     case EXTERNAL_FLOAT_ELEMENTS:
278     case EXTERNAL_DOUBLE_ELEMENTS:
279     case EXTERNAL_PIXEL_ELEMENTS:
280       KeyedLoadStubCompiler::GenerateLoadExternalArray(masm, elements_kind_);
281       break;
282     case DICTIONARY_ELEMENTS:
283       KeyedLoadStubCompiler::GenerateLoadDictionaryElement(masm);
284       break;
285     case NON_STRICT_ARGUMENTS_ELEMENTS:
286       UNREACHABLE();
287       break;
288   }
289 }
290
291
292 void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
293   switch (elements_kind_) {
294     case FAST_ELEMENTS:
295     case FAST_SMI_ONLY_ELEMENTS: {
296       KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
297                                                        is_js_array_,
298                                                        elements_kind_,
299                                                        grow_mode_);
300     }
301       break;
302     case FAST_DOUBLE_ELEMENTS:
303       KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
304                                                              is_js_array_,
305                                                              grow_mode_);
306       break;
307     case EXTERNAL_BYTE_ELEMENTS:
308     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
309     case EXTERNAL_SHORT_ELEMENTS:
310     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
311     case EXTERNAL_INT_ELEMENTS:
312     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
313     case EXTERNAL_FLOAT_ELEMENTS:
314     case EXTERNAL_DOUBLE_ELEMENTS:
315     case EXTERNAL_PIXEL_ELEMENTS:
316       KeyedStoreStubCompiler::GenerateStoreExternalArray(masm, elements_kind_);
317       break;
318     case DICTIONARY_ELEMENTS:
319       KeyedStoreStubCompiler::GenerateStoreDictionaryElement(masm);
320       break;
321     case NON_STRICT_ARGUMENTS_ELEMENTS:
322       UNREACHABLE();
323       break;
324   }
325 }
326
327
328 void ArgumentsAccessStub::PrintName(StringStream* stream) {
329   stream->Add("ArgumentsAccessStub_");
330   switch (type_) {
331     case READ_ELEMENT: stream->Add("ReadElement"); break;
332     case NEW_NON_STRICT_FAST: stream->Add("NewNonStrictFast"); break;
333     case NEW_NON_STRICT_SLOW: stream->Add("NewNonStrictSlow"); break;
334     case NEW_STRICT: stream->Add("NewStrict"); break;
335   }
336 }
337
338
339 void CallFunctionStub::PrintName(StringStream* stream) {
340   stream->Add("CallFunctionStub_Args%d", argc_);
341   if (ReceiverMightBeImplicit()) stream->Add("_Implicit");
342   if (RecordCallTarget()) stream->Add("_Recording");
343 }
344
345
346 void CallConstructStub::PrintName(StringStream* stream) {
347   stream->Add("CallConstructStub");
348   if (RecordCallTarget()) stream->Add("_Recording");
349 }
350
351
352 void ToBooleanStub::PrintName(StringStream* stream) {
353   stream->Add("ToBooleanStub_");
354   types_.Print(stream);
355 }
356
357
358 void ToBooleanStub::Types::Print(StringStream* stream) const {
359   if (IsEmpty()) stream->Add("None");
360   if (Contains(UNDEFINED)) stream->Add("Undefined");
361   if (Contains(BOOLEAN)) stream->Add("Bool");
362   if (Contains(NULL_TYPE)) stream->Add("Null");
363   if (Contains(SMI)) stream->Add("Smi");
364   if (Contains(SPEC_OBJECT)) stream->Add("SpecObject");
365   if (Contains(STRING)) stream->Add("String");
366   if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber");
367 }
368
369
370 void ToBooleanStub::Types::TraceTransition(Types to) const {
371   if (!FLAG_trace_ic) return;
372   char buffer[100];
373   NoAllocationStringAllocator allocator(buffer,
374                                         static_cast<unsigned>(sizeof(buffer)));
375   StringStream stream(&allocator);
376   stream.Add("[ToBooleanIC (");
377   Print(&stream);
378   stream.Add("->");
379   to.Print(&stream);
380   stream.Add(")]\n");
381   stream.OutputToStdOut();
382 }
383
384
385 bool ToBooleanStub::Types::Record(Handle<Object> object) {
386   if (object->IsUndefined()) {
387     Add(UNDEFINED);
388     return false;
389   } else if (object->IsBoolean()) {
390     Add(BOOLEAN);
391     return object->IsTrue();
392   } else if (object->IsNull()) {
393     Add(NULL_TYPE);
394     return false;
395   } else if (object->IsSmi()) {
396     Add(SMI);
397     return Smi::cast(*object)->value() != 0;
398   } else if (object->IsSpecObject()) {
399     Add(SPEC_OBJECT);
400     return !object->IsUndetectableObject();
401   } else if (object->IsString()) {
402     Add(STRING);
403     return !object->IsUndetectableObject() &&
404         String::cast(*object)->length() != 0;
405   } else if (object->IsHeapNumber()) {
406     ASSERT(!object->IsUndetectableObject());
407     Add(HEAP_NUMBER);
408     double value = HeapNumber::cast(*object)->value();
409     return value != 0 && !isnan(value);
410   } else {
411     // We should never see an internal object at runtime here!
412     UNREACHABLE();
413     return true;
414   }
415 }
416
417
418 bool ToBooleanStub::Types::NeedsMap() const {
419   return Contains(ToBooleanStub::SPEC_OBJECT)
420       || Contains(ToBooleanStub::STRING)
421       || Contains(ToBooleanStub::HEAP_NUMBER);
422 }
423
424
425 bool ToBooleanStub::Types::CanBeUndetectable() const {
426   return Contains(ToBooleanStub::SPEC_OBJECT)
427       || Contains(ToBooleanStub::STRING);
428 }
429
430
431 void ElementsTransitionAndStoreStub::Generate(MacroAssembler* masm) {
432   Label fail;
433   if (!FLAG_trace_elements_transitions) {
434     if (to_ == FAST_ELEMENTS) {
435       if (from_ == FAST_SMI_ONLY_ELEMENTS) {
436         ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
437       } else if (from_ == FAST_DOUBLE_ELEMENTS) {
438         ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail);
439       } else {
440         UNREACHABLE();
441       }
442       KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
443                                                        is_jsarray_,
444                                                        FAST_ELEMENTS,
445                                                        grow_mode_);
446     } else if (from_ == FAST_SMI_ONLY_ELEMENTS && to_ == FAST_DOUBLE_ELEMENTS) {
447       ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
448       KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
449                                                              is_jsarray_,
450                                                              grow_mode_);
451     } else {
452       UNREACHABLE();
453     }
454   }
455   masm->bind(&fail);
456   KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode_);
457 }
458
459 } }  // namespace v8::internal