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