blob: 00da4cba623a3fa61834e5d22326260fd9b754d6 [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// 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"
Ben Murdoch257744e2011-11-30 15:57:28 +000032#include "stub-cache.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000033#include "factory.h"
Ben Murdochb8e0da22011-05-16 14:20:40 +010034#include "gdb-jit.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000035#include "macro-assembler.h"
36
37namespace v8 {
38namespace internal {
39
Leon Clarkee46be812010-01-19 14:06:41 +000040bool CodeStub::FindCodeInCache(Code** code_out) {
Steve Block44f0eee2011-05-26 01:26:41 +010041 Heap* heap = Isolate::Current()->heap();
42 int index = heap->code_stubs()->FindEntry(GetKey());
Leon Clarkee46be812010-01-19 14:06:41 +000043 if (index != NumberDictionary::kNotFound) {
Steve Block44f0eee2011-05-26 01:26:41 +010044 *code_out = Code::cast(heap->code_stubs()->ValueAt(index));
Leon Clarkee46be812010-01-19 14:06:41 +000045 return true;
Steve Blockd0582a62009-12-15 09:54:21 +000046 }
Leon Clarkee46be812010-01-19 14:06:41 +000047 return false;
48}
Steve Blockd0582a62009-12-15 09:54:21 +000049
Leon Clarkee46be812010-01-19 14:06:41 +000050
51void CodeStub::GenerateCode(MacroAssembler* masm) {
52 // Update the static counter each time a new code stub is generated.
Steve Block44f0eee2011-05-26 01:26:41 +010053 masm->isolate()->counters()->code_stubs()->Increment();
Ben Murdoch086aeea2011-05-13 15:57:08 +010054
Leon Clarkee46be812010-01-19 14:06:41 +000055 // Nested stubs are not allowed for leafs.
Ben Murdoch086aeea2011-05-13 15:57:08 +010056 AllowStubCallsScope allow_scope(masm, AllowsStubCalls());
57
Leon Clarkee46be812010-01-19 14:06:41 +000058 // Generate the code for the stub.
59 masm->set_generating_stub(true);
60 Generate(masm);
61}
62
63
Ben Murdoch589d6972011-11-30 16:04:58 +000064SmartArrayPointer<const char> CodeStub::GetName() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000065 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
Leon Clarkee46be812010-01-19 14:06:41 +000074void CodeStub::RecordCodeGeneration(Code* code, MacroAssembler* masm) {
75 code->set_major_key(MajorKey());
76
Steve Block44f0eee2011-05-26 01:26:41 +010077 Isolate* isolate = masm->isolate();
Ben Murdoch589d6972011-11-30 16:04:58 +000078 SmartArrayPointer<const char> name = GetName();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000079 PROFILE(isolate, CodeCreateEvent(Logger::STUB_TAG, code, *name));
80 GDBJIT(AddCode(GDBJITInterface::STUB, *name, code));
Steve Block44f0eee2011-05-26 01:26:41 +010081 Counters* counters = isolate->counters();
82 counters->total_stubs_code_size()->Increment(code->instruction_size());
Leon Clarkee46be812010-01-19 14:06:41 +000083
84#ifdef ENABLE_DISASSEMBLER
85 if (FLAG_print_code_stubs) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000086 code->Disassemble(*name);
Leon Clarkee46be812010-01-19 14:06:41 +000087 PrintF("\n");
88 }
89#endif
90}
91
92
Steve Block6ded16b2010-05-10 14:33:55 +010093int CodeStub::GetCodeKind() {
94 return Code::STUB;
95}
96
97
Leon Clarkee46be812010-01-19 14:06:41 +000098Handle<Code> CodeStub::GetCode() {
Steve Block44f0eee2011-05-26 01:26:41 +010099 Isolate* isolate = Isolate::Current();
100 Factory* factory = isolate->factory();
101 Heap* heap = isolate->heap();
Leon Clarkee46be812010-01-19 14:06:41 +0000102 Code* code;
103 if (!FindCodeInCache(&code)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100104 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000105
Steve Blocka7e24c12009-10-30 11:49:00 +0000106 // Generate the new code.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100107 MacroAssembler masm(isolate, NULL, 256);
Leon Clarkee46be812010-01-19 14:06:41 +0000108 GenerateCode(&masm);
Steve Blocka7e24c12009-10-30 11:49:00 +0000109
110 // Create the code object.
111 CodeDesc desc;
112 masm.GetCode(&desc);
113
Leon Clarkee46be812010-01-19 14:06:41 +0000114 // Copy the generated code into a heap object.
Steve Block6ded16b2010-05-10 14:33:55 +0100115 Code::Flags flags = Code::ComputeFlags(
116 static_cast<Code::Kind>(GetCodeKind()),
Steve Block6ded16b2010-05-10 14:33:55 +0100117 GetICState());
Steve Block44f0eee2011-05-26 01:26:41 +0100118 Handle<Code> new_object = factory->NewCode(
119 desc, flags, masm.CodeObject(), NeedsImmovableCode());
Leon Clarkee46be812010-01-19 14:06:41 +0000120 RecordCodeGeneration(*new_object, &masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100121 FinishCode(*new_object);
Steve Blocka7e24c12009-10-30 11:49:00 +0000122
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800123 // Update the dictionary and the root in Heap.
124 Handle<NumberDictionary> dict =
Steve Block44f0eee2011-05-26 01:26:41 +0100125 factory->DictionaryAtNumberPut(
126 Handle<NumberDictionary>(heap->code_stubs()),
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800127 GetKey(),
128 new_object);
Steve Block44f0eee2011-05-26 01:26:41 +0100129 heap->public_set_code_stubs(*dict);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800130
Leon Clarkee46be812010-01-19 14:06:41 +0000131 code = *new_object;
Steve Blocka7e24c12009-10-30 11:49:00 +0000132 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000133
Steve Block44f0eee2011-05-26 01:26:41 +0100134 ASSERT(!NeedsImmovableCode() || heap->lo_space()->Contains(code));
135 return Handle<Code>(code, isolate);
Leon Clarkee46be812010-01-19 14:06:41 +0000136}
137
138
John Reck59135872010-11-02 12:39:01 -0700139MaybeObject* CodeStub::TryGetCode() {
Leon Clarkee46be812010-01-19 14:06:41 +0000140 Code* code;
141 if (!FindCodeInCache(&code)) {
142 // Generate the new code.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100143 MacroAssembler masm(Isolate::Current(), NULL, 256);
Leon Clarkee46be812010-01-19 14:06:41 +0000144 GenerateCode(&masm);
Steve Block44f0eee2011-05-26 01:26:41 +0100145 Heap* heap = masm.isolate()->heap();
Leon Clarkee46be812010-01-19 14:06:41 +0000146
147 // Create the code object.
148 CodeDesc desc;
149 masm.GetCode(&desc);
150
151 // Try to copy the generated code into a heap object.
Steve Block6ded16b2010-05-10 14:33:55 +0100152 Code::Flags flags = Code::ComputeFlags(
153 static_cast<Code::Kind>(GetCodeKind()),
Steve Block6ded16b2010-05-10 14:33:55 +0100154 GetICState());
John Reck59135872010-11-02 12:39:01 -0700155 Object* new_object;
156 { MaybeObject* maybe_new_object =
Steve Block44f0eee2011-05-26 01:26:41 +0100157 heap->CreateCode(desc, flags, masm.CodeObject());
John Reck59135872010-11-02 12:39:01 -0700158 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
159 }
Leon Clarkee46be812010-01-19 14:06:41 +0000160 code = Code::cast(new_object);
161 RecordCodeGeneration(code, &masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100162 FinishCode(code);
Leon Clarkee46be812010-01-19 14:06:41 +0000163
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800164 // Try to update the code cache but do not fail if unable.
165 MaybeObject* maybe_new_object =
Steve Block44f0eee2011-05-26 01:26:41 +0100166 heap->code_stubs()->AtNumberPut(GetKey(), code);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800167 if (maybe_new_object->ToObject(&new_object)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100168 heap->public_set_code_stubs(NumberDictionary::cast(new_object));
Leon Clarkee46be812010-01-19 14:06:41 +0000169 }
170 }
171
172 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000173}
174
175
Andrei Popescu31002712010-02-23 13:46:05 +0000176const char* CodeStub::MajorName(CodeStub::Major major_key,
177 bool allow_unknown_keys) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000178 switch (major_key) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000179#define DEF_CASE(name) case name: return #name "Stub";
Steve Blockd0582a62009-12-15 09:54:21 +0000180 CODE_STUB_LIST(DEF_CASE)
181#undef DEF_CASE
Steve Blocka7e24c12009-10-30 11:49:00 +0000182 default:
Andrei Popescu31002712010-02-23 13:46:05 +0000183 if (!allow_unknown_keys) {
184 UNREACHABLE();
185 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000186 return NULL;
187 }
188}
189
190
Ben Murdochb0fe1622011-05-05 13:52:32 +0100191int ICCompareStub::MinorKey() {
192 return OpField::encode(op_ - Token::EQ) | StateField::encode(state_);
193}
194
195
196void ICCompareStub::Generate(MacroAssembler* masm) {
197 switch (state_) {
198 case CompareIC::UNINITIALIZED:
199 GenerateMiss(masm);
200 break;
201 case CompareIC::SMIS:
202 GenerateSmis(masm);
203 break;
204 case CompareIC::HEAP_NUMBERS:
205 GenerateHeapNumbers(masm);
206 break;
Ben Murdoch257744e2011-11-30 15:57:28 +0000207 case CompareIC::STRINGS:
208 GenerateStrings(masm);
209 break;
210 case CompareIC::SYMBOLS:
211 GenerateSymbols(masm);
212 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100213 case CompareIC::OBJECTS:
214 GenerateObjects(masm);
215 break;
216 default:
217 UNREACHABLE();
218 }
219}
220
221
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000222void InstanceofStub::PrintName(StringStream* stream) {
Ben Murdoch086aeea2011-05-13 15:57:08 +0100223 const char* args = "";
224 if (HasArgsInRegisters()) {
225 args = "_REGS";
226 }
227
228 const char* inline_check = "";
229 if (HasCallSiteInlineCheck()) {
230 inline_check = "_INLINE";
231 }
232
233 const char* return_true_false_object = "";
234 if (ReturnTrueFalseObject()) {
235 return_true_false_object = "_TRUEFALSE";
236 }
237
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000238 stream->Add("InstanceofStub%s%s%s",
239 args,
240 inline_check,
241 return_true_false_object);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100242}
243
244
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000245void KeyedLoadElementStub::Generate(MacroAssembler* masm) {
246 switch (elements_kind_) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000247 case FAST_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000248 KeyedLoadStubCompiler::GenerateLoadFastElement(masm);
249 break;
Ben Murdoch589d6972011-11-30 16:04:58 +0000250 case FAST_DOUBLE_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000251 KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(masm);
252 break;
Ben Murdoch589d6972011-11-30 16:04:58 +0000253 case EXTERNAL_BYTE_ELEMENTS:
254 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
255 case EXTERNAL_SHORT_ELEMENTS:
256 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
257 case EXTERNAL_INT_ELEMENTS:
258 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
259 case EXTERNAL_FLOAT_ELEMENTS:
260 case EXTERNAL_DOUBLE_ELEMENTS:
261 case EXTERNAL_PIXEL_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000262 KeyedLoadStubCompiler::GenerateLoadExternalArray(masm, elements_kind_);
263 break;
Ben Murdoch589d6972011-11-30 16:04:58 +0000264 case DICTIONARY_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000265 KeyedLoadStubCompiler::GenerateLoadDictionaryElement(masm);
266 break;
Ben Murdoch589d6972011-11-30 16:04:58 +0000267 case NON_STRICT_ARGUMENTS_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000268 UNREACHABLE();
269 break;
270 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000271}
272
273
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000274void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
275 switch (elements_kind_) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000276 case FAST_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000277 KeyedStoreStubCompiler::GenerateStoreFastElement(masm, is_js_array_);
278 break;
Ben Murdoch589d6972011-11-30 16:04:58 +0000279 case FAST_DOUBLE_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000280 KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
281 is_js_array_);
282 break;
Ben Murdoch589d6972011-11-30 16:04:58 +0000283 case EXTERNAL_BYTE_ELEMENTS:
284 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
285 case EXTERNAL_SHORT_ELEMENTS:
286 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
287 case EXTERNAL_INT_ELEMENTS:
288 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
289 case EXTERNAL_FLOAT_ELEMENTS:
290 case EXTERNAL_DOUBLE_ELEMENTS:
291 case EXTERNAL_PIXEL_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000292 KeyedStoreStubCompiler::GenerateStoreExternalArray(masm, elements_kind_);
293 break;
Ben Murdoch589d6972011-11-30 16:04:58 +0000294 case DICTIONARY_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000295 KeyedStoreStubCompiler::GenerateStoreDictionaryElement(masm);
296 break;
Ben Murdoch589d6972011-11-30 16:04:58 +0000297 case NON_STRICT_ARGUMENTS_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000298 UNREACHABLE();
299 break;
300 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000301}
302
303
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000304void ArgumentsAccessStub::PrintName(StringStream* stream) {
305 const char* type_name = NULL; // Make g++ happy.
306 switch (type_) {
307 case READ_ELEMENT: type_name = "ReadElement"; break;
308 case NEW_NON_STRICT_FAST: type_name = "NewNonStrictFast"; break;
309 case NEW_NON_STRICT_SLOW: type_name = "NewNonStrictSlow"; break;
310 case NEW_STRICT: type_name = "NewStrict"; break;
311 }
312 stream->Add("ArgumentsAccessStub_%s", type_name);
Ben Murdoch257744e2011-11-30 15:57:28 +0000313}
314
315
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000316void CallFunctionStub::PrintName(StringStream* stream) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000317 const char* flags_name = NULL; // Make g++ happy.
318 switch (flags_) {
319 case NO_CALL_FUNCTION_FLAGS: flags_name = ""; break;
320 case RECEIVER_MIGHT_BE_IMPLICIT: flags_name = "_Implicit"; break;
321 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000322 stream->Add("CallFunctionStub_Args%d%s", argc_, flags_name);
Ben Murdoch257744e2011-11-30 15:57:28 +0000323}
324
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000325
326void ToBooleanStub::PrintName(StringStream* stream) {
327 stream->Add("ToBooleanStub_");
328 types_.Print(stream);
329}
330
331
332void ToBooleanStub::Types::Print(StringStream* stream) const {
333 if (IsEmpty()) stream->Add("None");
334 if (Contains(UNDEFINED)) stream->Add("Undefined");
335 if (Contains(BOOLEAN)) stream->Add("Bool");
336 if (Contains(NULL_TYPE)) stream->Add("Null");
337 if (Contains(SMI)) stream->Add("Smi");
338 if (Contains(SPEC_OBJECT)) stream->Add("SpecObject");
339 if (Contains(STRING)) stream->Add("String");
340 if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber");
341}
342
343
344void ToBooleanStub::Types::TraceTransition(Types to) const {
345 if (!FLAG_trace_ic) return;
346 char buffer[100];
347 NoAllocationStringAllocator allocator(buffer,
348 static_cast<unsigned>(sizeof(buffer)));
349 StringStream stream(&allocator);
350 stream.Add("[ToBooleanIC (");
351 Print(&stream);
352 stream.Add("->");
353 to.Print(&stream);
354 stream.Add(")]\n");
355 stream.OutputToStdOut();
356}
357
358
359bool ToBooleanStub::Types::Record(Handle<Object> object) {
360 if (object->IsUndefined()) {
361 Add(UNDEFINED);
362 return false;
363 } else if (object->IsBoolean()) {
364 Add(BOOLEAN);
365 return object->IsTrue();
366 } else if (object->IsNull()) {
367 Add(NULL_TYPE);
368 return false;
369 } else if (object->IsSmi()) {
370 Add(SMI);
371 return Smi::cast(*object)->value() != 0;
372 } else if (object->IsSpecObject()) {
373 Add(SPEC_OBJECT);
374 return !object->IsUndetectableObject();
375 } else if (object->IsString()) {
376 Add(STRING);
377 return !object->IsUndetectableObject() &&
378 String::cast(*object)->length() != 0;
379 } else if (object->IsHeapNumber()) {
380 ASSERT(!object->IsUndetectableObject());
381 Add(HEAP_NUMBER);
382 double value = HeapNumber::cast(*object)->value();
383 return value != 0 && !isnan(value);
384 } else {
385 // We should never see an internal object at runtime here!
386 UNREACHABLE();
387 return true;
388 }
389}
390
391
392bool ToBooleanStub::Types::NeedsMap() const {
393 return Contains(ToBooleanStub::SPEC_OBJECT)
394 || Contains(ToBooleanStub::STRING)
395 || Contains(ToBooleanStub::HEAP_NUMBER);
396}
397
398
399bool ToBooleanStub::Types::CanBeUndetectable() const {
400 return Contains(ToBooleanStub::SPEC_OBJECT)
401 || Contains(ToBooleanStub::STRING);
402}
403
404
Steve Blocka7e24c12009-10-30 11:49:00 +0000405} } // namespace v8::internal