code-stubs.cc revision 69a99ed0b2b2ef69d393c371b03db3a98aaf880e
1// Copyright 2011 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
37namespace v8 {
38namespace internal {
39
40bool CodeStub::FindCodeInCache(Code** code_out) {
41  Heap* heap = Isolate::Current()->heap();
42  int index = heap->code_stubs()->FindEntry(GetKey());
43  if (index != NumberDictionary::kNotFound) {
44    *code_out = Code::cast(heap->code_stubs()->ValueAt(index));
45    return true;
46  }
47  return false;
48}
49
50
51void 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 leafs.
56  AllowStubCallsScope allow_scope(masm, AllowsStubCalls());
57
58  // Generate the code for the stub.
59  masm->set_generating_stub(true);
60  Generate(masm);
61}
62
63
64SmartPointer<const char> CodeStub::GetName() {
65  char buffer[100];
66  NoAllocationStringAllocator allocator(buffer,
67                                        static_cast<unsigned>(sizeof(buffer)));
68  StringStream stream(&allocator);
69  PrintName(&stream);
70  return stream.ToCString();
71}
72
73
74void CodeStub::RecordCodeGeneration(Code* code, MacroAssembler* masm) {
75  code->set_major_key(MajorKey());
76
77  Isolate* isolate = masm->isolate();
78  SmartPointer<const char> name = GetName();
79  PROFILE(isolate, CodeCreateEvent(Logger::STUB_TAG, code, *name));
80  GDBJIT(AddCode(GDBJITInterface::STUB, *name, code));
81  Counters* counters = isolate->counters();
82  counters->total_stubs_code_size()->Increment(code->instruction_size());
83
84#ifdef ENABLE_DISASSEMBLER
85  if (FLAG_print_code_stubs) {
86    code->Disassemble(*name);
87    PrintF("\n");
88  }
89#endif
90}
91
92
93int CodeStub::GetCodeKind() {
94  return Code::STUB;
95}
96
97
98Handle<Code> CodeStub::GetCode() {
99  Isolate* isolate = Isolate::Current();
100  Factory* factory = isolate->factory();
101  Heap* heap = isolate->heap();
102  Code* code;
103  if (!FindCodeInCache(&code)) {
104    HandleScope scope(isolate);
105
106    // Generate the new code.
107    MacroAssembler masm(isolate, NULL, 256);
108    GenerateCode(&masm);
109
110    // Create the code object.
111    CodeDesc desc;
112    masm.GetCode(&desc);
113
114    // Copy the generated code into a heap object.
115    Code::Flags flags = Code::ComputeFlags(
116        static_cast<Code::Kind>(GetCodeKind()),
117        InLoop(),
118        GetICState());
119    Handle<Code> new_object = factory->NewCode(
120        desc, flags, masm.CodeObject(), NeedsImmovableCode());
121    RecordCodeGeneration(*new_object, &masm);
122    FinishCode(*new_object);
123
124    // Update the dictionary and the root in Heap.
125    Handle<NumberDictionary> dict =
126        factory->DictionaryAtNumberPut(
127            Handle<NumberDictionary>(heap->code_stubs()),
128            GetKey(),
129            new_object);
130    heap->public_set_code_stubs(*dict);
131
132    code = *new_object;
133  }
134
135  ASSERT(!NeedsImmovableCode() || heap->lo_space()->Contains(code));
136  return Handle<Code>(code, isolate);
137}
138
139
140MaybeObject* CodeStub::TryGetCode() {
141  Code* code;
142  if (!FindCodeInCache(&code)) {
143    // Generate the new code.
144    MacroAssembler masm(Isolate::Current(), NULL, 256);
145    GenerateCode(&masm);
146    Heap* heap = masm.isolate()->heap();
147
148    // Create the code object.
149    CodeDesc desc;
150    masm.GetCode(&desc);
151
152    // Try to copy the generated code into a heap object.
153    Code::Flags flags = Code::ComputeFlags(
154        static_cast<Code::Kind>(GetCodeKind()),
155        InLoop(),
156        GetICState());
157    Object* new_object;
158    { MaybeObject* maybe_new_object =
159          heap->CreateCode(desc, flags, masm.CodeObject());
160      if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
161    }
162    code = Code::cast(new_object);
163    RecordCodeGeneration(code, &masm);
164    FinishCode(code);
165
166    // Try to update the code cache but do not fail if unable.
167    MaybeObject* maybe_new_object =
168        heap->code_stubs()->AtNumberPut(GetKey(), code);
169    if (maybe_new_object->ToObject(&new_object)) {
170      heap->public_set_code_stubs(NumberDictionary::cast(new_object));
171    }
172  }
173
174  return code;
175}
176
177
178const char* CodeStub::MajorName(CodeStub::Major major_key,
179                                bool allow_unknown_keys) {
180  switch (major_key) {
181#define DEF_CASE(name) case name: return #name "Stub";
182    CODE_STUB_LIST(DEF_CASE)
183#undef DEF_CASE
184    default:
185      if (!allow_unknown_keys) {
186        UNREACHABLE();
187      }
188      return NULL;
189  }
190}
191
192
193int ICCompareStub::MinorKey() {
194  return OpField::encode(op_ - Token::EQ) | StateField::encode(state_);
195}
196
197
198void ICCompareStub::Generate(MacroAssembler* masm) {
199  switch (state_) {
200    case CompareIC::UNINITIALIZED:
201      GenerateMiss(masm);
202      break;
203    case CompareIC::SMIS:
204      GenerateSmis(masm);
205      break;
206    case CompareIC::HEAP_NUMBERS:
207      GenerateHeapNumbers(masm);
208      break;
209    case CompareIC::STRINGS:
210      GenerateStrings(masm);
211      break;
212    case CompareIC::SYMBOLS:
213      GenerateSymbols(masm);
214      break;
215    case CompareIC::OBJECTS:
216      GenerateObjects(masm);
217      break;
218    default:
219      UNREACHABLE();
220  }
221}
222
223
224void InstanceofStub::PrintName(StringStream* stream) {
225  const char* args = "";
226  if (HasArgsInRegisters()) {
227    args = "_REGS";
228  }
229
230  const char* inline_check = "";
231  if (HasCallSiteInlineCheck()) {
232    inline_check = "_INLINE";
233  }
234
235  const char* return_true_false_object = "";
236  if (ReturnTrueFalseObject()) {
237    return_true_false_object = "_TRUEFALSE";
238  }
239
240  stream->Add("InstanceofStub%s%s%s",
241              args,
242              inline_check,
243              return_true_false_object);
244}
245
246
247void KeyedLoadElementStub::Generate(MacroAssembler* masm) {
248  switch (elements_kind_) {
249    case JSObject::FAST_ELEMENTS:
250      KeyedLoadStubCompiler::GenerateLoadFastElement(masm);
251      break;
252    case JSObject::FAST_DOUBLE_ELEMENTS:
253      KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(masm);
254      break;
255    case JSObject::EXTERNAL_BYTE_ELEMENTS:
256    case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
257    case JSObject::EXTERNAL_SHORT_ELEMENTS:
258    case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
259    case JSObject::EXTERNAL_INT_ELEMENTS:
260    case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
261    case JSObject::EXTERNAL_FLOAT_ELEMENTS:
262    case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
263    case JSObject::EXTERNAL_PIXEL_ELEMENTS:
264      KeyedLoadStubCompiler::GenerateLoadExternalArray(masm, elements_kind_);
265      break;
266    case JSObject::DICTIONARY_ELEMENTS:
267      KeyedLoadStubCompiler::GenerateLoadDictionaryElement(masm);
268      break;
269    case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
270      UNREACHABLE();
271      break;
272  }
273}
274
275
276void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
277  switch (elements_kind_) {
278    case JSObject::FAST_ELEMENTS:
279      KeyedStoreStubCompiler::GenerateStoreFastElement(masm, is_js_array_);
280      break;
281    case JSObject::FAST_DOUBLE_ELEMENTS:
282      KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
283                                                             is_js_array_);
284      break;
285    case JSObject::EXTERNAL_BYTE_ELEMENTS:
286    case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
287    case JSObject::EXTERNAL_SHORT_ELEMENTS:
288    case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
289    case JSObject::EXTERNAL_INT_ELEMENTS:
290    case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
291    case JSObject::EXTERNAL_FLOAT_ELEMENTS:
292    case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
293    case JSObject::EXTERNAL_PIXEL_ELEMENTS:
294      KeyedStoreStubCompiler::GenerateStoreExternalArray(masm, elements_kind_);
295      break;
296    case JSObject::DICTIONARY_ELEMENTS:
297      KeyedStoreStubCompiler::GenerateStoreDictionaryElement(masm);
298      break;
299    case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
300      UNREACHABLE();
301      break;
302  }
303}
304
305
306void ArgumentsAccessStub::PrintName(StringStream* stream) {
307  const char* type_name = NULL;  // Make g++ happy.
308  switch (type_) {
309    case READ_ELEMENT: type_name = "ReadElement"; break;
310    case NEW_NON_STRICT_FAST: type_name = "NewNonStrictFast"; break;
311    case NEW_NON_STRICT_SLOW: type_name = "NewNonStrictSlow"; break;
312    case NEW_STRICT: type_name = "NewStrict"; break;
313  }
314  stream->Add("ArgumentsAccessStub_%s", type_name);
315}
316
317
318void CallFunctionStub::PrintName(StringStream* stream) {
319  const char* in_loop_name = NULL;  // Make g++ happy.
320  switch (in_loop_) {
321    case NOT_IN_LOOP: in_loop_name = ""; break;
322    case IN_LOOP: in_loop_name = "_InLoop"; break;
323  }
324  const char* flags_name = NULL;  // Make g++ happy.
325  switch (flags_) {
326    case NO_CALL_FUNCTION_FLAGS: flags_name = ""; break;
327    case RECEIVER_MIGHT_BE_IMPLICIT: flags_name = "_Implicit"; break;
328  }
329  stream->Add("CallFunctionStub_Args%d%s%s", argc_, in_loop_name, flags_name);
330}
331
332
333void ToBooleanStub::PrintName(StringStream* stream) {
334  stream->Add("ToBooleanStub_");
335  types_.Print(stream);
336}
337
338
339void ToBooleanStub::Types::Print(StringStream* stream) const {
340  if (IsEmpty()) stream->Add("None");
341  if (Contains(UNDEFINED)) stream->Add("Undefined");
342  if (Contains(BOOLEAN)) stream->Add("Bool");
343  if (Contains(NULL_TYPE)) stream->Add("Null");
344  if (Contains(SMI)) stream->Add("Smi");
345  if (Contains(SPEC_OBJECT)) stream->Add("SpecObject");
346  if (Contains(STRING)) stream->Add("String");
347  if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber");
348}
349
350
351void ToBooleanStub::Types::TraceTransition(Types to) const {
352  if (!FLAG_trace_ic) return;
353  char buffer[100];
354  NoAllocationStringAllocator allocator(buffer,
355                                        static_cast<unsigned>(sizeof(buffer)));
356  StringStream stream(&allocator);
357  stream.Add("[ToBooleanIC (");
358  Print(&stream);
359  stream.Add("->");
360  to.Print(&stream);
361  stream.Add(")]\n");
362  stream.OutputToStdOut();
363}
364
365
366bool ToBooleanStub::Types::Record(Handle<Object> object) {
367  if (object->IsUndefined()) {
368    Add(UNDEFINED);
369    return false;
370  } else if (object->IsBoolean()) {
371    Add(BOOLEAN);
372    return object->IsTrue();
373  } else if (object->IsNull()) {
374    Add(NULL_TYPE);
375    return false;
376  } else if (object->IsSmi()) {
377    Add(SMI);
378    return Smi::cast(*object)->value() != 0;
379  } else if (object->IsSpecObject()) {
380    Add(SPEC_OBJECT);
381    return !object->IsUndetectableObject();
382  } else if (object->IsString()) {
383    Add(STRING);
384    return !object->IsUndetectableObject() &&
385        String::cast(*object)->length() != 0;
386  } else if (object->IsHeapNumber()) {
387    ASSERT(!object->IsUndetectableObject());
388    Add(HEAP_NUMBER);
389    double value = HeapNumber::cast(*object)->value();
390    return value != 0 && !isnan(value);
391  } else {
392    // We should never see an internal object at runtime here!
393    UNREACHABLE();
394    return true;
395  }
396}
397
398
399bool ToBooleanStub::Types::NeedsMap() const {
400  return Contains(ToBooleanStub::SPEC_OBJECT)
401      || Contains(ToBooleanStub::STRING)
402      || Contains(ToBooleanStub::HEAP_NUMBER);
403}
404
405
406bool ToBooleanStub::Types::CanBeUndetectable() const {
407  return Contains(ToBooleanStub::SPEC_OBJECT)
408      || Contains(ToBooleanStub::STRING);
409}
410
411
412} }  // namespace v8::internal
413