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
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.
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.
30
#include "bootstrapper.h"
31
#include "code-stubs.h"
32
#include "stub-cache.h"
35
#include "macro-assembler.h"
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));
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();
55
// Nested stubs are not allowed for leaves.
56
AllowStubCallsScope allow_scope(masm, false);
58
// Generate the code for the stub.
59
masm->set_generating_stub(true);
60
NoCurrentFrameScope scope(masm);
65
SmartArrayPointer<const char> CodeStub::GetName() {
67
NoAllocationStringAllocator allocator(buffer,
68
static_cast<unsigned>(sizeof(buffer)));
69
StringStream stream(&allocator);
71
return stream.ToCString();
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());
85
int CodeStub::GetCodeKind() {
90
Handle<Code> CodeStub::GetCode() {
91
Isolate* isolate = Isolate::Current();
92
Factory* factory = isolate->factory();
93
Heap* heap = isolate->heap();
96
? FindCodeInSpecialCache(&code)
97
: FindCodeInCache(&code)) {
98
ASSERT(IsPregenerated() == code->is_pregenerated());
99
return Handle<Code>(code);
103
HandleScope scope(isolate);
105
// Generate the new code.
106
MacroAssembler masm(isolate, NULL, 256);
109
// Create the code object.
113
// Copy the generated code into a heap object.
114
Code::Flags flags = Code::ComputeFlags(
115
static_cast<Code::Kind>(GetCodeKind()),
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);
123
#ifdef ENABLE_DISASSEMBLER
124
if (FLAG_print_code_stubs) {
125
new_object->Disassemble(*GetName());
130
if (UseSpecialCache()) {
131
AddToSpecialCache(new_object);
133
// Update the dictionary and the root in Heap.
134
Handle<UnseededNumberDictionary> dict =
135
factory->DictionaryAtNumberPut(
136
Handle<UnseededNumberDictionary>(heap->code_stubs()),
139
heap->public_set_code_stubs(*dict);
145
ASSERT(!NeedsImmovableCode() || heap->lo_space()->Contains(code));
146
return Handle<Code>(code, isolate);
150
const char* CodeStub::MajorName(CodeStub::Major major_key,
151
bool allow_unknown_keys) {
153
#define DEF_CASE(name) case name: return #name "Stub";
154
CODE_STUB_LIST(DEF_CASE)
157
if (!allow_unknown_keys) {
165
void CodeStub::PrintName(StringStream* stream) {
166
stream->Add("%s", MajorName(MajorKey(), false));
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_,
176
factory->strict_compare_ic_symbol() :
177
factory->compare_ic_symbol(),
182
bool ICCompareStub::FindCodeInSpecialCache(Code** code_out) {
183
Isolate* isolate = known_map_->GetIsolate();
184
Factory* factory = isolate->factory();
185
Code::Flags flags = Code::ComputeFlags(
186
static_cast<Code::Kind>(GetCodeKind()),
188
ASSERT(op_ == Token::EQ || op_ == Token::EQ_STRICT);
189
Handle<Object> probe(
190
known_map_->FindInCodeCache(
192
*factory->strict_compare_ic_symbol() :
193
*factory->compare_ic_symbol(),
195
if (probe->IsCode()) {
196
*code_out = Code::cast(*probe);
197
ASSERT(op_ == (*code_out)->compare_operation() + Token::EQ);
204
int ICCompareStub::MinorKey() {
205
return OpField::encode(op_ - Token::EQ) | StateField::encode(state_);
209
void ICCompareStub::Generate(MacroAssembler* masm) {
211
case CompareIC::UNINITIALIZED:
214
case CompareIC::SMIS:
217
case CompareIC::HEAP_NUMBERS:
218
GenerateHeapNumbers(masm);
220
case CompareIC::STRINGS:
221
GenerateStrings(masm);
223
case CompareIC::SYMBOLS:
224
GenerateSymbols(masm);
226
case CompareIC::OBJECTS:
227
GenerateObjects(masm);
229
case CompareIC::KNOWN_OBJECTS:
230
ASSERT(*known_map_ != NULL);
231
GenerateKnownObjects(masm);
239
void InstanceofStub::PrintName(StringStream* stream) {
240
const char* args = "";
241
if (HasArgsInRegisters()) {
245
const char* inline_check = "";
246
if (HasCallSiteInlineCheck()) {
247
inline_check = "_INLINE";
250
const char* return_true_false_object = "";
251
if (ReturnTrueFalseObject()) {
252
return_true_false_object = "_TRUEFALSE";
255
stream->Add("InstanceofStub%s%s%s",
258
return_true_false_object);
262
void JSEntryStub::FinishCode(Handle<Code> code) {
263
Handle<FixedArray> handler_table =
264
code->GetIsolate()->factory()->NewFixedArray(1, TENURED);
265
handler_table->set(0, Smi::FromInt(handler_offset_));
266
code->set_handler_table(*handler_table);
270
void KeyedLoadElementStub::Generate(MacroAssembler* masm) {
271
switch (elements_kind_) {
273
case FAST_HOLEY_ELEMENTS:
274
case FAST_SMI_ELEMENTS:
275
case FAST_HOLEY_SMI_ELEMENTS:
276
KeyedLoadStubCompiler::GenerateLoadFastElement(masm);
278
case FAST_DOUBLE_ELEMENTS:
279
case FAST_HOLEY_DOUBLE_ELEMENTS:
280
KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(masm);
282
case EXTERNAL_BYTE_ELEMENTS:
283
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
284
case EXTERNAL_SHORT_ELEMENTS:
285
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
286
case EXTERNAL_INT_ELEMENTS:
287
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
288
case EXTERNAL_FLOAT_ELEMENTS:
289
case EXTERNAL_DOUBLE_ELEMENTS:
290
case EXTERNAL_PIXEL_ELEMENTS:
291
KeyedLoadStubCompiler::GenerateLoadExternalArray(masm, elements_kind_);
293
case DICTIONARY_ELEMENTS:
294
KeyedLoadStubCompiler::GenerateLoadDictionaryElement(masm);
296
case NON_STRICT_ARGUMENTS_ELEMENTS:
303
void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
304
switch (elements_kind_) {
306
case FAST_HOLEY_ELEMENTS:
307
case FAST_SMI_ELEMENTS:
308
case FAST_HOLEY_SMI_ELEMENTS: {
309
KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
315
case FAST_DOUBLE_ELEMENTS:
316
case FAST_HOLEY_DOUBLE_ELEMENTS:
317
KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
321
case EXTERNAL_BYTE_ELEMENTS:
322
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
323
case EXTERNAL_SHORT_ELEMENTS:
324
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
325
case EXTERNAL_INT_ELEMENTS:
326
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
327
case EXTERNAL_FLOAT_ELEMENTS:
328
case EXTERNAL_DOUBLE_ELEMENTS:
329
case EXTERNAL_PIXEL_ELEMENTS:
330
KeyedStoreStubCompiler::GenerateStoreExternalArray(masm, elements_kind_);
332
case DICTIONARY_ELEMENTS:
333
KeyedStoreStubCompiler::GenerateStoreDictionaryElement(masm);
335
case NON_STRICT_ARGUMENTS_ELEMENTS:
342
void ArgumentsAccessStub::PrintName(StringStream* stream) {
343
stream->Add("ArgumentsAccessStub_");
345
case READ_ELEMENT: stream->Add("ReadElement"); break;
346
case NEW_NON_STRICT_FAST: stream->Add("NewNonStrictFast"); break;
347
case NEW_NON_STRICT_SLOW: stream->Add("NewNonStrictSlow"); break;
348
case NEW_STRICT: stream->Add("NewStrict"); break;
353
void CallFunctionStub::PrintName(StringStream* stream) {
354
stream->Add("CallFunctionStub_Args%d", argc_);
355
if (ReceiverMightBeImplicit()) stream->Add("_Implicit");
356
if (RecordCallTarget()) stream->Add("_Recording");
360
void CallConstructStub::PrintName(StringStream* stream) {
361
stream->Add("CallConstructStub");
362
if (RecordCallTarget()) stream->Add("_Recording");
366
void ToBooleanStub::PrintName(StringStream* stream) {
367
stream->Add("ToBooleanStub_");
368
types_.Print(stream);
372
void ToBooleanStub::Types::Print(StringStream* stream) const {
373
if (IsEmpty()) stream->Add("None");
374
if (Contains(UNDEFINED)) stream->Add("Undefined");
375
if (Contains(BOOLEAN)) stream->Add("Bool");
376
if (Contains(NULL_TYPE)) stream->Add("Null");
377
if (Contains(SMI)) stream->Add("Smi");
378
if (Contains(SPEC_OBJECT)) stream->Add("SpecObject");
379
if (Contains(STRING)) stream->Add("String");
380
if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber");
384
void ToBooleanStub::Types::TraceTransition(Types to) const {
385
if (!FLAG_trace_ic) return;
387
NoAllocationStringAllocator allocator(buffer,
388
static_cast<unsigned>(sizeof(buffer)));
389
StringStream stream(&allocator);
390
stream.Add("[ToBooleanIC (");
395
stream.OutputToStdOut();
399
bool ToBooleanStub::Types::Record(Handle<Object> object) {
400
if (object->IsUndefined()) {
403
} else if (object->IsBoolean()) {
405
return object->IsTrue();
406
} else if (object->IsNull()) {
409
} else if (object->IsSmi()) {
411
return Smi::cast(*object)->value() != 0;
412
} else if (object->IsSpecObject()) {
414
return !object->IsUndetectableObject();
415
} else if (object->IsString()) {
417
return !object->IsUndetectableObject() &&
418
String::cast(*object)->length() != 0;
419
} else if (object->IsHeapNumber()) {
420
ASSERT(!object->IsUndetectableObject());
422
double value = HeapNumber::cast(*object)->value();
423
return value != 0 && !isnan(value);
425
// We should never see an internal object at runtime here!
432
bool ToBooleanStub::Types::NeedsMap() const {
433
return Contains(ToBooleanStub::SPEC_OBJECT)
434
|| Contains(ToBooleanStub::STRING)
435
|| Contains(ToBooleanStub::HEAP_NUMBER);
439
bool ToBooleanStub::Types::CanBeUndetectable() const {
440
return Contains(ToBooleanStub::SPEC_OBJECT)
441
|| Contains(ToBooleanStub::STRING);
445
void ElementsTransitionAndStoreStub::Generate(MacroAssembler* masm) {
447
ASSERT(!IsFastHoleyElementsKind(from_) || IsFastHoleyElementsKind(to_));
448
if (!FLAG_trace_elements_transitions) {
449
if (IsFastSmiOrObjectElementsKind(to_)) {
450
if (IsFastSmiOrObjectElementsKind(from_)) {
451
ElementsTransitionGenerator::
452
GenerateMapChangeElementsTransition(masm);
453
} else if (IsFastDoubleElementsKind(from_)) {
454
ASSERT(!IsFastSmiElementsKind(to_));
455
ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail);
459
KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
463
} else if (IsFastSmiElementsKind(from_) &&
464
IsFastDoubleElementsKind(to_)) {
465
ElementsTransitionGenerator::GenerateSmiToDouble(masm, &fail);
466
KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
469
} else if (IsFastDoubleElementsKind(from_)) {
470
ASSERT(to_ == FAST_HOLEY_DOUBLE_ELEMENTS);
471
ElementsTransitionGenerator::
472
GenerateMapChangeElementsTransition(masm);
478
KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode_);
482
FunctionEntryHook ProfileEntryHookStub::entry_hook_ = NULL;
485
void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function,
486
intptr_t stack_pointer) {
487
if (entry_hook_ != NULL)
488
entry_hook_(function, stack_pointer);
492
bool ProfileEntryHookStub::SetFunctionEntryHook(FunctionEntryHook entry_hook) {
493
// We don't allow setting a new entry hook over one that's
494
// already active, as the hooks won't stack.
495
if (entry_hook != 0 && entry_hook_ != 0)
498
entry_hook_ = entry_hook;
503
} } // namespace v8::internal