blob: 1d1128f2d14c9d9a38a4f37fd54e0ceb5841e75f [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 Murdoch3fb3ca82011-12-02 17:19:32 +000064SmartPointer<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
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 Murdoch3fb3ca82011-12-02 17:19:32 +000078 SmartPointer<const char> name = GetName();
79 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()),
117 InLoop(),
118 GetICState());
Steve Block44f0eee2011-05-26 01:26:41 +0100119 Handle<Code> new_object = factory->NewCode(
120 desc, flags, masm.CodeObject(), NeedsImmovableCode());
Leon Clarkee46be812010-01-19 14:06:41 +0000121 RecordCodeGeneration(*new_object, &masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100122 FinishCode(*new_object);
Steve Blocka7e24c12009-10-30 11:49:00 +0000123
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800124 // Update the dictionary and the root in Heap.
125 Handle<NumberDictionary> dict =
Steve Block44f0eee2011-05-26 01:26:41 +0100126 factory->DictionaryAtNumberPut(
127 Handle<NumberDictionary>(heap->code_stubs()),
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800128 GetKey(),
129 new_object);
Steve Block44f0eee2011-05-26 01:26:41 +0100130 heap->public_set_code_stubs(*dict);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800131
Leon Clarkee46be812010-01-19 14:06:41 +0000132 code = *new_object;
Steve Blocka7e24c12009-10-30 11:49:00 +0000133 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000134
Steve Block44f0eee2011-05-26 01:26:41 +0100135 ASSERT(!NeedsImmovableCode() || heap->lo_space()->Contains(code));
136 return Handle<Code>(code, isolate);
Leon Clarkee46be812010-01-19 14:06:41 +0000137}
138
139
John Reck59135872010-11-02 12:39:01 -0700140MaybeObject* CodeStub::TryGetCode() {
Leon Clarkee46be812010-01-19 14:06:41 +0000141 Code* code;
142 if (!FindCodeInCache(&code)) {
143 // Generate the new code.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100144 MacroAssembler masm(Isolate::Current(), NULL, 256);
Leon Clarkee46be812010-01-19 14:06:41 +0000145 GenerateCode(&masm);
Steve Block44f0eee2011-05-26 01:26:41 +0100146 Heap* heap = masm.isolate()->heap();
Leon Clarkee46be812010-01-19 14:06:41 +0000147
148 // Create the code object.
149 CodeDesc desc;
150 masm.GetCode(&desc);
151
152 // Try to copy the generated code into a heap object.
Steve Block6ded16b2010-05-10 14:33:55 +0100153 Code::Flags flags = Code::ComputeFlags(
154 static_cast<Code::Kind>(GetCodeKind()),
155 InLoop(),
156 GetICState());
John Reck59135872010-11-02 12:39:01 -0700157 Object* new_object;
158 { MaybeObject* maybe_new_object =
Steve Block44f0eee2011-05-26 01:26:41 +0100159 heap->CreateCode(desc, flags, masm.CodeObject());
John Reck59135872010-11-02 12:39:01 -0700160 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
161 }
Leon Clarkee46be812010-01-19 14:06:41 +0000162 code = Code::cast(new_object);
163 RecordCodeGeneration(code, &masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100164 FinishCode(code);
Leon Clarkee46be812010-01-19 14:06:41 +0000165
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800166 // Try to update the code cache but do not fail if unable.
167 MaybeObject* maybe_new_object =
Steve Block44f0eee2011-05-26 01:26:41 +0100168 heap->code_stubs()->AtNumberPut(GetKey(), code);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800169 if (maybe_new_object->ToObject(&new_object)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100170 heap->public_set_code_stubs(NumberDictionary::cast(new_object));
Leon Clarkee46be812010-01-19 14:06:41 +0000171 }
172 }
173
174 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000175}
176
177
Andrei Popescu31002712010-02-23 13:46:05 +0000178const char* CodeStub::MajorName(CodeStub::Major major_key,
179 bool allow_unknown_keys) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000180 switch (major_key) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000181#define DEF_CASE(name) case name: return #name "Stub";
Steve Blockd0582a62009-12-15 09:54:21 +0000182 CODE_STUB_LIST(DEF_CASE)
183#undef DEF_CASE
Steve Blocka7e24c12009-10-30 11:49:00 +0000184 default:
Andrei Popescu31002712010-02-23 13:46:05 +0000185 if (!allow_unknown_keys) {
186 UNREACHABLE();
187 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000188 return NULL;
189 }
190}
191
192
Ben Murdochb0fe1622011-05-05 13:52:32 +0100193int 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;
Ben Murdoch257744e2011-11-30 15:57:28 +0000209 case CompareIC::STRINGS:
210 GenerateStrings(masm);
211 break;
212 case CompareIC::SYMBOLS:
213 GenerateSymbols(masm);
214 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100215 case CompareIC::OBJECTS:
216 GenerateObjects(masm);
217 break;
218 default:
219 UNREACHABLE();
220 }
221}
222
223
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000224void InstanceofStub::PrintName(StringStream* stream) {
Ben Murdoch086aeea2011-05-13 15:57:08 +0100225 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
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000240 stream->Add("InstanceofStub%s%s%s",
241 args,
242 inline_check,
243 return_true_false_object);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100244}
245
246
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000247void 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 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000273}
274
275
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000276void 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 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000303}
304
305
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000306void 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);
Ben Murdoch257744e2011-11-30 15:57:28 +0000315}
316
317
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000318void 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);
Ben Murdoch257744e2011-11-30 15:57:28 +0000330}
331
Steve Blocka7e24c12009-10-30 11:49:00 +0000332} } // namespace v8::internal