Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: src/x64/stub-cache-x64.cc

Issue 6066010: Merge 6095:6198 from bleeding_edge to experimental/gc. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/x64/regexp-macro-assembler-x64.cc ('k') | test/cctest/cctest.status » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution. 11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its 12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived 13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission. 14 // from this software without specific prior written permission.
15 // 15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 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. 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28
29 #include "v8.h" 28 #include "v8.h"
30 29
31 #if defined(V8_TARGET_ARCH_X64) 30 #if defined(V8_TARGET_ARCH_X64)
32 31
33 #include "ic-inl.h" 32 #include "ic-inl.h"
34 #include "code-stubs.h"
35 #include "codegen-inl.h" 33 #include "codegen-inl.h"
36 #include "stub-cache.h" 34 #include "stub-cache.h"
37 #include "macro-assembler.h"
38 35
39 namespace v8 { 36 namespace v8 {
40 namespace internal { 37 namespace internal {
41 38
42 //-----------------------------------------------------------------------------
43 // StubCompiler static helper functions
44
45 #define __ ACCESS_MASM(masm) 39 #define __ ACCESS_MASM(masm)
46 40
47 41
48 static void ProbeTable(MacroAssembler* masm, 42 static void ProbeTable(MacroAssembler* masm,
49 Code::Flags flags, 43 Code::Flags flags,
50 StubCache::Table table, 44 StubCache::Table table,
51 Register name, 45 Register name,
52 Register offset) { 46 Register offset) {
53 ASSERT_EQ(8, kPointerSize); 47 ASSERT_EQ(8, kPointerSize);
54 ASSERT_EQ(16, sizeof(StubCache::Entry)); 48 ASSERT_EQ(16, sizeof(StubCache::Entry));
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 // Give up probing if still not found the undefined value. 169 // Give up probing if still not found the undefined value.
176 __ j(not_equal, miss_label); 170 __ j(not_equal, miss_label);
177 } 171 }
178 } 172 }
179 173
180 __ bind(&done); 174 __ bind(&done);
181 __ DecrementCounter(&Counters::negative_lookups_miss, 1); 175 __ DecrementCounter(&Counters::negative_lookups_miss, 1);
182 } 176 }
183 177
184 178
185 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
186 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
187 Code* code = NULL;
188 if (kind == Code::LOAD_IC) {
189 code = Builtins::builtin(Builtins::LoadIC_Miss);
190 } else {
191 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
192 }
193
194 Handle<Code> ic(code);
195 __ Jump(ic, RelocInfo::CODE_TARGET);
196 }
197
198
199 void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
200 int index,
201 Register prototype) {
202 // Load the global or builtins object from the current context.
203 __ movq(prototype,
204 Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
205 // Load the global context from the global or builtins object.
206 __ movq(prototype,
207 FieldOperand(prototype, GlobalObject::kGlobalContextOffset));
208 // Load the function from the global context.
209 __ movq(prototype, Operand(prototype, Context::SlotOffset(index)));
210 // Load the initial map. The global functions all have initial maps.
211 __ movq(prototype,
212 FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
213 // Load the prototype from the initial map.
214 __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
215 }
216
217
218 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
219 MacroAssembler* masm, int index, Register prototype, Label* miss) {
220 // Check we're still in the same context.
221 __ Move(prototype, Top::global());
222 __ cmpq(Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)),
223 prototype);
224 __ j(not_equal, miss);
225 // Get the global function with the given index.
226 JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
227 // Load its initial map. The global functions all have initial maps.
228 __ Move(prototype, Handle<Map>(function->initial_map()));
229 // Load the prototype from the initial map.
230 __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
231 }
232
233
234 // Load a fast property out of a holder object (src). In-object properties
235 // are loaded directly otherwise the property is loaded from the properties
236 // fixed array.
237 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
238 Register dst, Register src,
239 JSObject* holder, int index) {
240 // Adjust for the number of properties stored in the holder.
241 index -= holder->map()->inobject_properties();
242 if (index < 0) {
243 // Get the property straight out of the holder.
244 int offset = holder->map()->instance_size() + (index * kPointerSize);
245 __ movq(dst, FieldOperand(src, offset));
246 } else {
247 // Calculate the offset into the properties array.
248 int offset = index * kPointerSize + FixedArray::kHeaderSize;
249 __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
250 __ movq(dst, FieldOperand(dst, offset));
251 }
252 }
253
254
255 static void PushInterceptorArguments(MacroAssembler* masm,
256 Register receiver,
257 Register holder,
258 Register name,
259 JSObject* holder_obj) {
260 __ push(name);
261 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
262 ASSERT(!Heap::InNewSpace(interceptor));
263 __ Move(kScratchRegister, Handle<Object>(interceptor));
264 __ push(kScratchRegister);
265 __ push(receiver);
266 __ push(holder);
267 __ push(FieldOperand(kScratchRegister, InterceptorInfo::kDataOffset));
268 }
269
270
271 void StubCache::GenerateProbe(MacroAssembler* masm, 179 void StubCache::GenerateProbe(MacroAssembler* masm,
272 Code::Flags flags, 180 Code::Flags flags,
273 Register receiver, 181 Register receiver,
274 Register name, 182 Register name,
275 Register scratch, 183 Register scratch,
276 Register extra, 184 Register extra,
277 Register extra2) { 185 Register extra2) {
278 Label miss; 186 Label miss;
279 USE(extra); // The register extra is not used on the X64 platform. 187 USE(extra); // The register extra is not used on the X64 platform.
280 USE(extra2); // The register extra2 is not used on the X64 platform. 188 USE(extra2); // The register extra2 is not used on the X64 platform.
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
317 225
318 // Probe the secondary table. 226 // Probe the secondary table.
319 ProbeTable(masm, flags, kSecondary, name, scratch); 227 ProbeTable(masm, flags, kSecondary, name, scratch);
320 228
321 // Cache miss: Fall-through and let caller handle the miss by 229 // Cache miss: Fall-through and let caller handle the miss by
322 // entering the runtime system. 230 // entering the runtime system.
323 __ bind(&miss); 231 __ bind(&miss);
324 } 232 }
325 233
326 234
327 // Both name_reg and receiver_reg are preserved on jumps to miss_label, 235 void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
328 // but may be destroyed if store is successful. 236 int index,
329 void StubCompiler::GenerateStoreField(MacroAssembler* masm, 237 Register prototype) {
330 JSObject* object, 238 // Load the global or builtins object from the current context.
331 int index, 239 __ movq(prototype,
332 Map* transition, 240 Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
333 Register receiver_reg, 241 // Load the global context from the global or builtins object.
334 Register name_reg, 242 __ movq(prototype,
335 Register scratch, 243 FieldOperand(prototype, GlobalObject::kGlobalContextOffset));
336 Label* miss_label) { 244 // Load the function from the global context.
337 // Check that the object isn't a smi. 245 __ movq(prototype, Operand(prototype, Context::SlotOffset(index)));
338 __ JumpIfSmi(receiver_reg, miss_label); 246 // Load the initial map. The global functions all have initial maps.
339 247 __ movq(prototype,
340 // Check that the map of the object hasn't changed. 248 FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
341 __ Cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset), 249 // Load the prototype from the initial map.
342 Handle<Map>(object->map())); 250 __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
343 __ j(not_equal, miss_label);
344
345 // Perform global security token check if needed.
346 if (object->IsJSGlobalProxy()) {
347 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
348 }
349
350 // Stub never generated for non-global objects that require access
351 // checks.
352 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
353
354 // Perform map transition for the receiver if necessary.
355 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
356 // The properties must be extended before we can store the value.
357 // We jump to a runtime call that extends the properties array.
358 __ pop(scratch); // Return address.
359 __ push(receiver_reg);
360 __ Push(Handle<Map>(transition));
361 __ push(rax);
362 __ push(scratch);
363 __ TailCallExternalReference(
364 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)), 3, 1);
365 return;
366 }
367
368 if (transition != NULL) {
369 // Update the map of the object; no write barrier updating is
370 // needed because the map is never in new space.
371 __ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset),
372 Handle<Map>(transition));
373 }
374
375 // Adjust for the number of properties stored in the object. Even in the
376 // face of a transition we can use the old map here because the size of the
377 // object and the number of in-object properties is not going to change.
378 index -= object->map()->inobject_properties();
379
380 if (index < 0) {
381 // Set the property straight into the object.
382 int offset = object->map()->instance_size() + (index * kPointerSize);
383 __ movq(FieldOperand(receiver_reg, offset), rax);
384
385 #ifdef ENABLE_CARDMARKING_WRITE_BARRIER
386 // Update the write barrier for the array address.
387 // Pass the value being stored in the now unused name_reg.
388 __ movq(name_reg, rax);
389 __ RecordWrite(receiver_reg, offset, name_reg, scratch);
390 #endif
391 } else {
392 // Write to the properties array.
393 int offset = index * kPointerSize + FixedArray::kHeaderSize;
394 // Get the properties array (optimistically).
395 __ movq(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
396 __ movq(FieldOperand(scratch, offset), rax);
397
398 #ifdef ENABLE_CARDMARKING_WRITE_BARRIER
399 // Update the write barrier for the array address.
400 // Pass the value being stored in the now unused name_reg.
401 __ movq(name_reg, rax);
402 __ RecordWrite(scratch, offset, name_reg, receiver_reg);
403 #endif
404 }
405
406 // Return the value (register rax).
407 __ ret(0);
408 } 251 }
409 252
410 253
254 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
255 MacroAssembler* masm, int index, Register prototype, Label* miss) {
256 // Check we're still in the same context.
257 __ Move(prototype, Top::global());
258 __ cmpq(Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)),
259 prototype);
260 __ j(not_equal, miss);
261 // Get the global function with the given index.
262 JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
263 // Load its initial map. The global functions all have initial maps.
264 __ Move(prototype, Handle<Map>(function->initial_map()));
265 // Load the prototype from the initial map.
266 __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
267 }
268
269
411 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm, 270 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
412 Register receiver, 271 Register receiver,
413 Register scratch, 272 Register scratch,
414 Label* miss_label) { 273 Label* miss_label) {
415 // Check that the receiver isn't a smi. 274 // Check that the receiver isn't a smi.
416 __ JumpIfSmi(receiver, miss_label); 275 __ JumpIfSmi(receiver, miss_label);
417 276
418 // Check that the object is a JS array. 277 // Check that the object is a JS array.
419 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch); 278 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
420 __ j(not_equal, miss_label); 279 __ j(not_equal, miss_label);
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
466 325
467 // Check if the wrapped value is a string and load the length 326 // Check if the wrapped value is a string and load the length
468 // directly if it is. 327 // directly if it is.
469 __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset)); 328 __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
470 GenerateStringCheck(masm, scratch2, scratch1, miss, miss); 329 GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
471 __ movq(rax, FieldOperand(scratch2, String::kLengthOffset)); 330 __ movq(rax, FieldOperand(scratch2, String::kLengthOffset));
472 __ ret(0); 331 __ ret(0);
473 } 332 }
474 333
475 334
335 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
336 Register receiver,
337 Register result,
338 Register scratch,
339 Label* miss_label) {
340 __ TryGetFunctionPrototype(receiver, result, miss_label);
341 if (!result.is(rax)) __ movq(rax, result);
342 __ ret(0);
343 }
344
345
346 // Load a fast property out of a holder object (src). In-object properties
347 // are loaded directly otherwise the property is loaded from the properties
348 // fixed array.
349 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
350 Register dst, Register src,
351 JSObject* holder, int index) {
352 // Adjust for the number of properties stored in the holder.
353 index -= holder->map()->inobject_properties();
354 if (index < 0) {
355 // Get the property straight out of the holder.
356 int offset = holder->map()->instance_size() + (index * kPointerSize);
357 __ movq(dst, FieldOperand(src, offset));
358 } else {
359 // Calculate the offset into the properties array.
360 int offset = index * kPointerSize + FixedArray::kHeaderSize;
361 __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
362 __ movq(dst, FieldOperand(dst, offset));
363 }
364 }
365
366
367 static void PushInterceptorArguments(MacroAssembler* masm,
368 Register receiver,
369 Register holder,
370 Register name,
371 JSObject* holder_obj) {
372 __ push(name);
373 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
374 ASSERT(!Heap::InNewSpace(interceptor));
375 __ Move(kScratchRegister, Handle<Object>(interceptor));
376 __ push(kScratchRegister);
377 __ push(receiver);
378 __ push(holder);
379 __ push(FieldOperand(kScratchRegister, InterceptorInfo::kDataOffset));
380 }
381
382
476 static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm, 383 static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
477 Register receiver, 384 Register receiver,
478 Register holder, 385 Register holder,
479 Register name, 386 Register name,
480 JSObject* holder_obj) { 387 JSObject* holder_obj) {
481 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); 388 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
482 389
483 ExternalReference ref = 390 ExternalReference ref =
484 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly)); 391 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly));
485 __ movq(rax, Immediate(5)); 392 __ movq(rax, Immediate(5));
486 __ movq(rbx, ref); 393 __ movq(rbx, ref);
487 394
488 CEntryStub stub(1); 395 CEntryStub stub(1);
489 __ CallStub(&stub); 396 __ CallStub(&stub);
490 } 397 }
491 398
492 399
493
494 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
495 Register receiver,
496 Register result,
497 Register scratch,
498 Label* miss_label) {
499 __ TryGetFunctionPrototype(receiver, result, miss_label);
500 if (!result.is(rax)) __ movq(rax, result);
501 __ ret(0);
502 }
503
504 // Number of pointers to be reserved on stack for fast API call. 400 // Number of pointers to be reserved on stack for fast API call.
505 static const int kFastApiCallArguments = 3; 401 static const int kFastApiCallArguments = 3;
506 402
403
507 // Reserves space for the extra arguments to API function in the 404 // Reserves space for the extra arguments to API function in the
508 // caller's frame. 405 // caller's frame.
509 // 406 //
510 // These arguments are set by CheckPrototypes and GenerateFastApiCall. 407 // These arguments are set by CheckPrototypes and GenerateFastApiCall.
511 static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { 408 static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
512 // ----------- S t a t e ------------- 409 // ----------- S t a t e -------------
513 // -- rsp[0] : return address 410 // -- rsp[0] : return address
514 // -- rsp[8] : last argument in the internal frame of the caller 411 // -- rsp[8] : last argument in the internal frame of the caller
515 // ----------------------------------- 412 // -----------------------------------
516 __ movq(scratch, Operand(rsp, 0)); 413 __ movq(scratch, Operand(rsp, 0));
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
550 // (last fast api call extra argument, 447 // (last fast api call extra argument,
551 // set by CheckPrototypes) 448 // set by CheckPrototypes)
552 // -- rsp[16] : api function 449 // -- rsp[16] : api function
553 // (first fast api call extra argument) 450 // (first fast api call extra argument)
554 // -- rsp[24] : api call data 451 // -- rsp[24] : api call data
555 // -- rsp[32] : last argument 452 // -- rsp[32] : last argument
556 // -- ... 453 // -- ...
557 // -- rsp[(argc + 3) * 8] : first argument 454 // -- rsp[(argc + 3) * 8] : first argument
558 // -- rsp[(argc + 4) * 8] : receiver 455 // -- rsp[(argc + 4) * 8] : receiver
559 // ----------------------------------- 456 // -----------------------------------
560
561 // Get the function and setup the context. 457 // Get the function and setup the context.
562 JSFunction* function = optimization.constant_function(); 458 JSFunction* function = optimization.constant_function();
563 __ Move(rdi, Handle<JSFunction>(function)); 459 __ Move(rdi, Handle<JSFunction>(function));
564 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); 460 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
565 461
566 // Pass the additional arguments. 462 // Pass the additional arguments.
567 __ movq(Operand(rsp, 2 * kPointerSize), rdi); 463 __ movq(Operand(rsp, 2 * kPointerSize), rdi);
568 Object* call_data = optimization.api_call_info()->data(); 464 Object* call_data = optimization.api_call_info()->data();
569 Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info()); 465 Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
570 if (Heap::InNewSpace(call_data)) { 466 if (Heap::InNewSpace(call_data)) {
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after
830 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); 726 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
831 __ j(not_equal, interceptor_succeeded); 727 __ j(not_equal, interceptor_succeeded);
832 } 728 }
833 729
834 StubCompiler* stub_compiler_; 730 StubCompiler* stub_compiler_;
835 const ParameterCount& arguments_; 731 const ParameterCount& arguments_;
836 Register name_; 732 Register name_;
837 }; 733 };
838 734
839 735
736 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
737 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
738 Code* code = NULL;
739 if (kind == Code::LOAD_IC) {
740 code = Builtins::builtin(Builtins::LoadIC_Miss);
741 } else {
742 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
743 }
744
745 Handle<Code> ic(code);
746 __ Jump(ic, RelocInfo::CODE_TARGET);
747 }
748
749
750 // Both name_reg and receiver_reg are preserved on jumps to miss_label,
751 // but may be destroyed if store is successful.
752 void StubCompiler::GenerateStoreField(MacroAssembler* masm,
753 JSObject* object,
754 int index,
755 Map* transition,
756 Register receiver_reg,
757 Register name_reg,
758 Register scratch,
759 Label* miss_label) {
760 // Check that the object isn't a smi.
761 __ JumpIfSmi(receiver_reg, miss_label);
762
763 // Check that the map of the object hasn't changed.
764 __ Cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
765 Handle<Map>(object->map()));
766 __ j(not_equal, miss_label);
767
768 // Perform global security token check if needed.
769 if (object->IsJSGlobalProxy()) {
770 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
771 }
772
773 // Stub never generated for non-global objects that require access
774 // checks.
775 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
776
777 // Perform map transition for the receiver if necessary.
778 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
779 // The properties must be extended before we can store the value.
780 // We jump to a runtime call that extends the properties array.
781 __ pop(scratch); // Return address.
782 __ push(receiver_reg);
783 __ Push(Handle<Map>(transition));
784 __ push(rax);
785 __ push(scratch);
786 __ TailCallExternalReference(
787 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)), 3, 1);
788 return;
789 }
790
791 if (transition != NULL) {
792 // Update the map of the object; no write barrier updating is
793 // needed because the map is never in new space.
794 __ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset),
795 Handle<Map>(transition));
796 }
797
798 // Adjust for the number of properties stored in the object. Even in the
799 // face of a transition we can use the old map here because the size of the
800 // object and the number of in-object properties is not going to change.
801 index -= object->map()->inobject_properties();
802
803 if (index < 0) {
804 // Set the property straight into the object.
805 int offset = object->map()->instance_size() + (index * kPointerSize);
806 __ movq(FieldOperand(receiver_reg, offset), rax);
807
808 // Update the write barrier for the array address.
809 // Pass the value being stored in the now unused name_reg.
810 #ifdef ENABLE_CARDMARKING_WRITE_BARRIER
811 __ movq(name_reg, rax);
812 __ RecordWrite(receiver_reg, offset, name_reg, scratch);
813 #endif
814 } else {
815 // Write to the properties array.
816 int offset = index * kPointerSize + FixedArray::kHeaderSize;
817 // Get the properties array (optimistically).
818 __ movq(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
819 __ movq(FieldOperand(scratch, offset), rax);
820
821 // Update the write barrier for the array address.
822 // Pass the value being stored in the now unused name_reg.
823 #ifdef ENABLE_CARDMARKING_WRITE_BARRIER
824 __ movq(name_reg, rax);
825 __ RecordWrite(scratch, offset, name_reg, receiver_reg);
826 #endif
827 }
828
829 // Return the value (register rax).
830 __ ret(0);
831 }
832
833
840 // Generate code to check that a global property cell is empty. Create 834 // Generate code to check that a global property cell is empty. Create
841 // the property cell at compilation time if no cell exists for the 835 // the property cell at compilation time if no cell exists for the
842 // property. 836 // property.
843 MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell( 837 MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell(
844 MacroAssembler* masm, 838 MacroAssembler* masm,
845 GlobalObject* global, 839 GlobalObject* global,
846 String* name, 840 String* name,
847 Register scratch, 841 Register scratch,
848 Label* miss) { 842 Label* miss) {
849 Object* probe; 843 Object* probe;
850 { MaybeObject* maybe_probe = global->EnsurePropertyCell(name); 844 { MaybeObject* maybe_probe = global->EnsurePropertyCell(name);
851 if (!maybe_probe->ToObject(&probe)) return maybe_probe; 845 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
852 } 846 }
853 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); 847 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
854 ASSERT(cell->value()->IsTheHole()); 848 ASSERT(cell->value()->IsTheHole());
855 __ Move(scratch, Handle<Object>(cell)); 849 __ Move(scratch, Handle<Object>(cell));
856 __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), 850 __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
857 Factory::the_hole_value()); 851 Factory::the_hole_value());
858 __ j(not_equal, miss); 852 __ j(not_equal, miss);
859 return cell; 853 return cell;
860 } 854 }
861 855
862 856
863 #undef __ 857 #undef __
864
865 #define __ ACCESS_MASM((masm())) 858 #define __ ACCESS_MASM((masm()))
866 859
867 860
861 Register StubCompiler::CheckPrototypes(JSObject* object,
862 Register object_reg,
863 JSObject* holder,
864 Register holder_reg,
865 Register scratch1,
866 Register scratch2,
867 String* name,
868 int save_at_depth,
869 Label* miss) {
870 // Make sure there's no overlap between holder and object registers.
871 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
872 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
873 && !scratch2.is(scratch1));
874
875 // Keep track of the current object in register reg. On the first
876 // iteration, reg is an alias for object_reg, on later iterations,
877 // it is an alias for holder_reg.
878 Register reg = object_reg;
879 int depth = 0;
880
881 if (save_at_depth == depth) {
882 __ movq(Operand(rsp, kPointerSize), object_reg);
883 }
884
885 // Check the maps in the prototype chain.
886 // Traverse the prototype chain from the object and do map checks.
887 JSObject* current = object;
888 while (current != holder) {
889 depth++;
890
891 // Only global objects and objects that do not require access
892 // checks are allowed in stubs.
893 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
894
895 JSObject* prototype = JSObject::cast(current->GetPrototype());
896 if (!current->HasFastProperties() &&
897 !current->IsJSGlobalObject() &&
898 !current->IsJSGlobalProxy()) {
899 if (!name->IsSymbol()) {
900 MaybeObject* lookup_result = Heap::LookupSymbol(name);
901 if (lookup_result->IsFailure()) {
902 set_failure(Failure::cast(lookup_result));
903 return reg;
904 } else {
905 name = String::cast(lookup_result->ToObjectUnchecked());
906 }
907 }
908 ASSERT(current->property_dictionary()->FindEntry(name) ==
909 StringDictionary::kNotFound);
910
911 GenerateDictionaryNegativeLookup(masm(),
912 miss,
913 reg,
914 name,
915 scratch1,
916 scratch2);
917 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
918 reg = holder_reg; // from now the object is in holder_reg
919 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
920 } else if (Heap::InNewSpace(prototype)) {
921 // Get the map of the current object.
922 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
923 __ Cmp(scratch1, Handle<Map>(current->map()));
924 // Branch on the result of the map check.
925 __ j(not_equal, miss);
926 // Check access rights to the global object. This has to happen
927 // after the map check so that we know that the object is
928 // actually a global object.
929 if (current->IsJSGlobalProxy()) {
930 __ CheckAccessGlobalProxy(reg, scratch1, miss);
931
932 // Restore scratch register to be the map of the object.
933 // We load the prototype from the map in the scratch register.
934 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
935 }
936 // The prototype is in new space; we cannot store a reference
937 // to it in the code. Load it from the map.
938 reg = holder_reg; // from now the object is in holder_reg
939 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
940
941 } else {
942 // Check the map of the current object.
943 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset),
944 Handle<Map>(current->map()));
945 // Branch on the result of the map check.
946 __ j(not_equal, miss);
947 // Check access rights to the global object. This has to happen
948 // after the map check so that we know that the object is
949 // actually a global object.
950 if (current->IsJSGlobalProxy()) {
951 __ CheckAccessGlobalProxy(reg, scratch1, miss);
952 }
953 // The prototype is in old space; load it directly.
954 reg = holder_reg; // from now the object is in holder_reg
955 __ Move(reg, Handle<JSObject>(prototype));
956 }
957
958 if (save_at_depth == depth) {
959 __ movq(Operand(rsp, kPointerSize), reg);
960 }
961
962 // Go to the next object in the prototype chain.
963 current = prototype;
964 }
965
966 // Check the holder map.
967 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), Handle<Map>(holder->map()));
968 __ j(not_equal, miss);
969
970 // Log the check depth.
971 LOG(IntEvent("check-maps-depth", depth + 1));
972
973 // Perform security check for access to the global object and return
974 // the holder register.
975 ASSERT(current == holder);
976 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
977 if (current->IsJSGlobalProxy()) {
978 __ CheckAccessGlobalProxy(reg, scratch1, miss);
979 }
980
981 // If we've skipped any global objects, it's not enough to verify
982 // that their maps haven't changed. We also need to check that the
983 // property cell for the property is still empty.
984 current = object;
985 while (current != holder) {
986 if (current->IsGlobalObject()) {
987 MaybeObject* cell = GenerateCheckPropertyCell(masm(),
988 GlobalObject::cast(current),
989 name,
990 scratch1,
991 miss);
992 if (cell->IsFailure()) {
993 set_failure(Failure::cast(cell));
994 return reg;
995 }
996 }
997 current = JSObject::cast(current->GetPrototype());
998 }
999
1000 // Return the register containing the holder.
1001 return reg;
1002 }
1003
1004
1005 void StubCompiler::GenerateLoadField(JSObject* object,
1006 JSObject* holder,
1007 Register receiver,
1008 Register scratch1,
1009 Register scratch2,
1010 Register scratch3,
1011 int index,
1012 String* name,
1013 Label* miss) {
1014 // Check that the receiver isn't a smi.
1015 __ JumpIfSmi(receiver, miss);
1016
1017 // Check the prototype chain.
1018 Register reg =
1019 CheckPrototypes(object, receiver, holder,
1020 scratch1, scratch2, scratch3, name, miss);
1021
1022 // Get the value from the properties.
1023 GenerateFastPropertyLoad(masm(), rax, reg, holder, index);
1024 __ ret(0);
1025 }
1026
1027
1028 bool StubCompiler::GenerateLoadCallback(JSObject* object,
1029 JSObject* holder,
1030 Register receiver,
1031 Register name_reg,
1032 Register scratch1,
1033 Register scratch2,
1034 Register scratch3,
1035 AccessorInfo* callback,
1036 String* name,
1037 Label* miss,
1038 Failure** failure) {
1039 // Check that the receiver isn't a smi.
1040 __ JumpIfSmi(receiver, miss);
1041
1042 // Check that the maps haven't changed.
1043 Register reg =
1044 CheckPrototypes(object, receiver, holder, scratch1,
1045 scratch2, scratch3, name, miss);
1046
1047 Handle<AccessorInfo> callback_handle(callback);
1048
1049 // Insert additional parameters into the stack frame above return address.
1050 ASSERT(!scratch2.is(reg));
1051 __ pop(scratch2); // Get return address to place it below.
1052
1053 __ push(receiver); // receiver
1054 __ push(reg); // holder
1055 if (Heap::InNewSpace(callback_handle->data())) {
1056 __ Move(scratch1, callback_handle);
1057 __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); // data
1058 } else {
1059 __ Push(Handle<Object>(callback_handle->data()));
1060 }
1061 __ push(name_reg); // name
1062 // Save a pointer to where we pushed the arguments pointer.
1063 // This will be passed as the const AccessorInfo& to the C++ callback.
1064
1065 #ifdef _WIN64
1066 // Win64 uses first register--rcx--for returned value.
1067 Register accessor_info_arg = r8;
1068 Register name_arg = rdx;
1069 #else
1070 Register accessor_info_arg = rsi;
1071 Register name_arg = rdi;
1072 #endif
1073
1074 ASSERT(!name_arg.is(scratch2));
1075 __ movq(name_arg, rsp);
1076 __ push(scratch2); // Restore return address.
1077
1078 // Do call through the api.
1079 Address getter_address = v8::ToCData<Address>(callback->getter());
1080 ApiFunction fun(getter_address);
1081
1082 // 3 elements array for v8::Agruments::values_ and handler for name.
1083 const int kStackSpace = 4;
1084
1085 // Allocate v8::AccessorInfo in non-GCed stack space.
1086 const int kArgStackSpace = 1;
1087
1088 __ PrepareCallApiFunction(kArgStackSpace);
1089 __ lea(rax, Operand(name_arg, 3 * kPointerSize));
1090
1091 // v8::AccessorInfo::args_.
1092 __ movq(StackSpaceOperand(0), rax);
1093
1094 // The context register (rsi) has been saved in PrepareCallApiFunction and
1095 // could be used to pass arguments.
1096 __ lea(accessor_info_arg, StackSpaceOperand(0));
1097
1098 // Emitting a stub call may try to allocate (if the code is not
1099 // already generated). Do not allow the assembler to perform a
1100 // garbage collection but instead return the allocation failure
1101 // object.
1102 MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace);
1103 if (result->IsFailure()) {
1104 *failure = Failure::cast(result);
1105 return false;
1106 }
1107 return true;
1108 }
1109
1110
1111 void StubCompiler::GenerateLoadConstant(JSObject* object,
1112 JSObject* holder,
1113 Register receiver,
1114 Register scratch1,
1115 Register scratch2,
1116 Register scratch3,
1117 Object* value,
1118 String* name,
1119 Label* miss) {
1120 // Check that the receiver isn't a smi.
1121 __ JumpIfSmi(receiver, miss);
1122
1123 // Check that the maps haven't changed.
1124 Register reg =
1125 CheckPrototypes(object, receiver, holder,
1126 scratch1, scratch2, scratch3, name, miss);
1127
1128 // Return the constant value.
1129 __ Move(rax, Handle<Object>(value));
1130 __ ret(0);
1131 }
1132
1133
1134 void StubCompiler::GenerateLoadInterceptor(JSObject* object,
1135 JSObject* interceptor_holder,
1136 LookupResult* lookup,
1137 Register receiver,
1138 Register name_reg,
1139 Register scratch1,
1140 Register scratch2,
1141 Register scratch3,
1142 String* name,
1143 Label* miss) {
1144 ASSERT(interceptor_holder->HasNamedInterceptor());
1145 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1146
1147 // Check that the receiver isn't a smi.
1148 __ JumpIfSmi(receiver, miss);
1149
1150 // So far the most popular follow ups for interceptor loads are FIELD
1151 // and CALLBACKS, so inline only them, other cases may be added
1152 // later.
1153 bool compile_followup_inline = false;
1154 if (lookup->IsProperty() && lookup->IsCacheable()) {
1155 if (lookup->type() == FIELD) {
1156 compile_followup_inline = true;
1157 } else if (lookup->type() == CALLBACKS &&
1158 lookup->GetCallbackObject()->IsAccessorInfo() &&
1159 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
1160 compile_followup_inline = true;
1161 }
1162 }
1163
1164 if (compile_followup_inline) {
1165 // Compile the interceptor call, followed by inline code to load the
1166 // property from further up the prototype chain if the call fails.
1167 // Check that the maps haven't changed.
1168 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1169 scratch1, scratch2, scratch3,
1170 name, miss);
1171 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1172
1173 // Save necessary data before invoking an interceptor.
1174 // Requires a frame to make GC aware of pushed pointers.
1175 __ EnterInternalFrame();
1176
1177 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1178 // CALLBACKS case needs a receiver to be passed into C++ callback.
1179 __ push(receiver);
1180 }
1181 __ push(holder_reg);
1182 __ push(name_reg);
1183
1184 // Invoke an interceptor. Note: map checks from receiver to
1185 // interceptor's holder has been compiled before (see a caller
1186 // of this method.)
1187 CompileCallLoadPropertyWithInterceptor(masm(),
1188 receiver,
1189 holder_reg,
1190 name_reg,
1191 interceptor_holder);
1192
1193 // Check if interceptor provided a value for property. If it's
1194 // the case, return immediately.
1195 Label interceptor_failed;
1196 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
1197 __ j(equal, &interceptor_failed);
1198 __ LeaveInternalFrame();
1199 __ ret(0);
1200
1201 __ bind(&interceptor_failed);
1202 __ pop(name_reg);
1203 __ pop(holder_reg);
1204 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1205 __ pop(receiver);
1206 }
1207
1208 __ LeaveInternalFrame();
1209
1210 // Check that the maps from interceptor's holder to lookup's holder
1211 // haven't changed. And load lookup's holder into |holder| register.
1212 if (interceptor_holder != lookup->holder()) {
1213 holder_reg = CheckPrototypes(interceptor_holder,
1214 holder_reg,
1215 lookup->holder(),
1216 scratch1,
1217 scratch2,
1218 scratch3,
1219 name,
1220 miss);
1221 }
1222
1223 if (lookup->type() == FIELD) {
1224 // We found FIELD property in prototype chain of interceptor's holder.
1225 // Retrieve a field from field's holder.
1226 GenerateFastPropertyLoad(masm(), rax, holder_reg,
1227 lookup->holder(), lookup->GetFieldIndex());
1228 __ ret(0);
1229 } else {
1230 // We found CALLBACKS property in prototype chain of interceptor's
1231 // holder.
1232 ASSERT(lookup->type() == CALLBACKS);
1233 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
1234 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1235 ASSERT(callback != NULL);
1236 ASSERT(callback->getter() != NULL);
1237
1238 // Tail call to runtime.
1239 // Important invariant in CALLBACKS case: the code above must be
1240 // structured to never clobber |receiver| register.
1241 __ pop(scratch2); // return address
1242 __ push(receiver);
1243 __ push(holder_reg);
1244 __ Move(holder_reg, Handle<AccessorInfo>(callback));
1245 __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
1246 __ push(holder_reg);
1247 __ push(name_reg);
1248 __ push(scratch2); // restore return address
1249
1250 ExternalReference ref =
1251 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
1252 __ TailCallExternalReference(ref, 5, 1);
1253 }
1254 } else { // !compile_followup_inline
1255 // Call the runtime system to load the interceptor.
1256 // Check that the maps haven't changed.
1257 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1258 scratch1, scratch2, scratch3,
1259 name, miss);
1260 __ pop(scratch2); // save old return address
1261 PushInterceptorArguments(masm(), receiver, holder_reg,
1262 name_reg, interceptor_holder);
1263 __ push(scratch2); // restore old return address
1264
1265 ExternalReference ref = ExternalReference(
1266 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
1267 __ TailCallExternalReference(ref, 5, 1);
1268 }
1269 }
1270
1271
868 void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) { 1272 void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
869 if (kind_ == Code::KEYED_CALL_IC) { 1273 if (kind_ == Code::KEYED_CALL_IC) {
870 __ Cmp(rcx, Handle<String>(name)); 1274 __ Cmp(rcx, Handle<String>(name));
871 __ j(not_equal, miss); 1275 __ j(not_equal, miss);
872 } 1276 }
873 } 1277 }
874 1278
875 1279
876 void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object, 1280 void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
877 JSObject* holder, 1281 JSObject* holder,
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
929 MaybeObject* CallStubCompiler::GenerateMissBranch() { 1333 MaybeObject* CallStubCompiler::GenerateMissBranch() {
930 MaybeObject* maybe_obj = 1334 MaybeObject* maybe_obj =
931 StubCache::ComputeCallMiss(arguments().immediate(), kind_); 1335 StubCache::ComputeCallMiss(arguments().immediate(), kind_);
932 Object* obj; 1336 Object* obj;
933 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1337 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
934 __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET); 1338 __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
935 return obj; 1339 return obj;
936 } 1340 }
937 1341
938 1342
939 MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
940 JSObject* holder,
941 JSFunction* function,
942 String* name,
943 CheckType check) {
944 // ----------- S t a t e -------------
945 // rcx : function name
946 // rsp[0] : return address
947 // rsp[8] : argument argc
948 // rsp[16] : argument argc - 1
949 // ...
950 // rsp[argc * 8] : argument 1
951 // rsp[(argc + 1) * 8] : argument 0 = receiver
952 // -----------------------------------
953
954 SharedFunctionInfo* function_info = function->shared();
955 if (function_info->HasBuiltinFunctionId()) {
956 BuiltinFunctionId id = function_info->builtin_function_id();
957 MaybeObject* maybe_result = CompileCustomCall(
958 id, object, holder, NULL, function, name);
959 Object* result;
960 if (!maybe_result->ToObject(&result)) return maybe_result;
961 // undefined means bail out to regular compiler.
962 if (!result->IsUndefined()) return result;
963 }
964
965 Label miss_in_smi_check;
966
967 GenerateNameCheck(name, &miss_in_smi_check);
968
969 // Get the receiver from the stack.
970 const int argc = arguments().immediate();
971 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
972
973 // Check that the receiver isn't a smi.
974 if (check != NUMBER_CHECK) {
975 __ JumpIfSmi(rdx, &miss_in_smi_check);
976 }
977
978 // Make sure that it's okay not to patch the on stack receiver
979 // unless we're doing a receiver map check.
980 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
981
982 CallOptimization optimization(function);
983 int depth = kInvalidProtoDepth;
984 Label miss;
985
986 switch (check) {
987 case RECEIVER_MAP_CHECK:
988 __ IncrementCounter(&Counters::call_const, 1);
989
990 if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
991 depth = optimization.GetPrototypeDepthOfExpectedType(
992 JSObject::cast(object), holder);
993 }
994
995 if (depth != kInvalidProtoDepth) {
996 __ IncrementCounter(&Counters::call_const_fast_api, 1);
997 // Allocate space for v8::Arguments implicit values. Must be initialized
998 // before to call any runtime function.
999 __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
1000 }
1001
1002 // Check that the maps haven't changed.
1003 CheckPrototypes(JSObject::cast(object), rdx, holder,
1004 rbx, rax, rdi, name, depth, &miss);
1005
1006 // Patch the receiver on the stack with the global proxy if
1007 // necessary.
1008 if (object->IsGlobalObject()) {
1009 ASSERT(depth == kInvalidProtoDepth);
1010 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
1011 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
1012 }
1013 break;
1014
1015 case STRING_CHECK:
1016 if (!function->IsBuiltin()) {
1017 // Calling non-builtins with a value as receiver requires boxing.
1018 __ jmp(&miss);
1019 } else {
1020 // Check that the object is a two-byte string or a symbol.
1021 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax);
1022 __ j(above_equal, &miss);
1023 // Check that the maps starting from the prototype haven't changed.
1024 GenerateDirectLoadGlobalFunctionPrototype(
1025 masm(), Context::STRING_FUNCTION_INDEX, rax, &miss);
1026 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
1027 rbx, rdx, rdi, name, &miss);
1028 }
1029 break;
1030
1031 case NUMBER_CHECK: {
1032 if (!function->IsBuiltin()) {
1033 // Calling non-builtins with a value as receiver requires boxing.
1034 __ jmp(&miss);
1035 } else {
1036 Label fast;
1037 // Check that the object is a smi or a heap number.
1038 __ JumpIfSmi(rdx, &fast);
1039 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax);
1040 __ j(not_equal, &miss);
1041 __ bind(&fast);
1042 // Check that the maps starting from the prototype haven't changed.
1043 GenerateDirectLoadGlobalFunctionPrototype(
1044 masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss);
1045 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
1046 rbx, rdx, rdi, name, &miss);
1047 }
1048 break;
1049 }
1050
1051 case BOOLEAN_CHECK: {
1052 if (!function->IsBuiltin()) {
1053 // Calling non-builtins with a value as receiver requires boxing.
1054 __ jmp(&miss);
1055 } else {
1056 Label fast;
1057 // Check that the object is a boolean.
1058 __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
1059 __ j(equal, &fast);
1060 __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
1061 __ j(not_equal, &miss);
1062 __ bind(&fast);
1063 // Check that the maps starting from the prototype haven't changed.
1064 GenerateDirectLoadGlobalFunctionPrototype(
1065 masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss);
1066 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
1067 rbx, rdx, rdi, name, &miss);
1068 }
1069 break;
1070 }
1071
1072 default:
1073 UNREACHABLE();
1074 }
1075
1076 if (depth != kInvalidProtoDepth) {
1077 Failure* failure;
1078 // Move the return address on top of the stack.
1079 __ movq(rax, Operand(rsp, 3 * kPointerSize));
1080 __ movq(Operand(rsp, 0 * kPointerSize), rax);
1081
1082 // rsp[2 * kPointerSize] is uninitialized, rsp[3 * kPointerSize] contains
1083 // duplicate of return address and will be overwritten.
1084 bool success = GenerateFastApiCall(masm(), optimization, argc, &failure);
1085 if (!success) {
1086 return failure;
1087 }
1088 } else {
1089 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1090 }
1091
1092 // Handle call cache miss.
1093 __ bind(&miss);
1094 if (depth != kInvalidProtoDepth) {
1095 __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
1096 }
1097
1098 // Handle call cache miss.
1099 __ bind(&miss_in_smi_check);
1100 Object* obj;
1101 { MaybeObject* maybe_obj = GenerateMissBranch();
1102 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1103 }
1104
1105 // Return the generated code.
1106 return GetCode(function);
1107 }
1108
1109
1110 MaybeObject* CallStubCompiler::CompileCallField(JSObject* object, 1343 MaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
1111 JSObject* holder, 1344 JSObject* holder,
1112 int index, 1345 int index,
1113 String* name) { 1346 String* name) {
1114 // ----------- S t a t e ------------- 1347 // ----------- S t a t e -------------
1115 // rcx : function name 1348 // rcx : function name
1116 // rsp[0] : return address 1349 // rsp[0] : return address
1117 // rsp[8] : argument argc 1350 // rsp[8] : argument argc
1118 // rsp[16] : argument argc - 1 1351 // rsp[16] : argument argc - 1
1119 // ... 1352 // ...
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
1251 #endif 1484 #endif
1252 1485
1253 __ bind(&exit); 1486 __ bind(&exit);
1254 __ ret((argc + 1) * kPointerSize); 1487 __ ret((argc + 1) * kPointerSize);
1255 1488
1256 #ifdef ENABLE_CARDMARKING_WRITE_BARRIER 1489 #ifdef ENABLE_CARDMARKING_WRITE_BARRIER
1257 __ bind(&with_write_barrier); 1490 __ bind(&with_write_barrier);
1258 1491
1259 __ InNewSpace(rbx, rcx, equal, &exit); 1492 __ InNewSpace(rbx, rcx, equal, &exit);
1260 1493
1261 RecordWriteStub stub(rbx, rdx, rcx); 1494 __ RecordWriteHelper(rbx, rdx, rcx);
1262 __ CallStub(&stub);
1263 1495
1264 __ ret((argc + 1) * kPointerSize); 1496 __ ret((argc + 1) * kPointerSize);
1265 #endif 1497 #endif
1266 1498
1267 __ bind(&attempt_to_grow_elements); 1499 __ bind(&attempt_to_grow_elements);
1268 if (!FLAG_inline_new) { 1500 if (!FLAG_inline_new) {
1269 __ jmp(&call_builtin); 1501 __ jmp(&call_builtin);
1270 } 1502 }
1271 1503
1272 ExternalReference new_space_allocation_top = 1504 ExternalReference new_space_allocation_top =
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
1412 Object* obj; 1644 Object* obj;
1413 { MaybeObject* maybe_obj = GenerateMissBranch(); 1645 { MaybeObject* maybe_obj = GenerateMissBranch();
1414 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1646 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1415 } 1647 }
1416 1648
1417 // Return the generated code. 1649 // Return the generated code.
1418 return GetCode(function); 1650 return GetCode(function);
1419 } 1651 }
1420 1652
1421 1653
1422 MaybeObject* CallStubCompiler::CompileStringCharAtCall( 1654 MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
1423 Object* object, 1655 Object* object,
1424 JSObject* holder, 1656 JSObject* holder,
1425 JSGlobalPropertyCell* cell, 1657 JSGlobalPropertyCell* cell,
1426 JSFunction* function, 1658 JSFunction* function,
1427 String* name) { 1659 String* name) {
1428 // ----------- S t a t e ------------- 1660 // ----------- S t a t e -------------
1429 // -- rcx : function name 1661 // -- rcx : function name
1430 // -- rsp[0] : return address 1662 // -- rsp[0] : return address
1431 // -- rsp[(argc - n) * 8] : arg[n] (zero-based) 1663 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1432 // -- ... 1664 // -- ...
(...skipping 12 matching lines...) Expand all
1445 1677
1446 // Check that the maps starting from the prototype haven't changed. 1678 // Check that the maps starting from the prototype haven't changed.
1447 GenerateDirectLoadGlobalFunctionPrototype(masm(), 1679 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1448 Context::STRING_FUNCTION_INDEX, 1680 Context::STRING_FUNCTION_INDEX,
1449 rax, 1681 rax,
1450 &miss); 1682 &miss);
1451 ASSERT(object != holder); 1683 ASSERT(object != holder);
1452 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, 1684 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
1453 rbx, rdx, rdi, name, &miss); 1685 rbx, rdx, rdi, name, &miss);
1454 1686
1455 Register receiver = rax; 1687 Register receiver = rbx;
1456 Register index = rdi; 1688 Register index = rdi;
1457 Register scratch1 = rbx; 1689 Register scratch = rdx;
1458 Register scratch2 = rdx;
1459 Register result = rax; 1690 Register result = rax;
1460 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize)); 1691 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
1461 if (argc > 0) { 1692 if (argc > 0) {
1462 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize)); 1693 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
1463 } else { 1694 } else {
1464 __ LoadRoot(index, Heap::kUndefinedValueRootIndex); 1695 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1465 } 1696 }
1466 1697
1467 StringCharAtGenerator char_at_generator(receiver, 1698 StringCharCodeAtGenerator char_code_at_generator(receiver,
1468 index, 1699 index,
1469 scratch1, 1700 scratch,
1470 scratch2, 1701 result,
1471 result, 1702 &miss, // When not a string.
1472 &miss, // When not a string. 1703 &miss, // When not a number.
1473 &miss, // When not a number. 1704 &index_out_of_range,
1474 &index_out_of_range, 1705 STRING_INDEX_IS_NUMBER);
1475 STRING_INDEX_IS_NUMBER); 1706 char_code_at_generator.GenerateFast(masm());
1476 char_at_generator.GenerateFast(masm());
1477 __ ret((argc + 1) * kPointerSize); 1707 __ ret((argc + 1) * kPointerSize);
1478 1708
1479 StubRuntimeCallHelper call_helper; 1709 StubRuntimeCallHelper call_helper;
1480 char_at_generator.GenerateSlow(masm(), call_helper); 1710 char_code_at_generator.GenerateSlow(masm(), call_helper);
1481 1711
1482 __ bind(&index_out_of_range); 1712 __ bind(&index_out_of_range);
1483 __ LoadRoot(rax, Heap::kEmptyStringRootIndex); 1713 __ LoadRoot(rax, Heap::kNanValueRootIndex);
1484 __ ret((argc + 1) * kPointerSize); 1714 __ ret((argc + 1) * kPointerSize);
1485 1715
1486 __ bind(&miss); 1716 __ bind(&miss);
1487 Object* obj; 1717 Object* obj;
1488 { MaybeObject* maybe_obj = GenerateMissBranch(); 1718 { MaybeObject* maybe_obj = GenerateMissBranch();
1489 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1719 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1490 } 1720 }
1491 1721
1492 // Return the generated code. 1722 // Return the generated code.
1493 return GetCode(function); 1723 return GetCode(function);
1494 } 1724 }
1495 1725
1496 1726
1497 MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( 1727 MaybeObject* CallStubCompiler::CompileStringCharAtCall(
1498 Object* object, 1728 Object* object,
1499 JSObject* holder, 1729 JSObject* holder,
1500 JSGlobalPropertyCell* cell, 1730 JSGlobalPropertyCell* cell,
1501 JSFunction* function, 1731 JSFunction* function,
1502 String* name) { 1732 String* name) {
1503 // ----------- S t a t e ------------- 1733 // ----------- S t a t e -------------
1504 // -- rcx : function name 1734 // -- rcx : function name
1505 // -- rsp[0] : return address 1735 // -- rsp[0] : return address
1506 // -- rsp[(argc - n) * 8] : arg[n] (zero-based) 1736 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1507 // -- ... 1737 // -- ...
1508 // -- rsp[(argc + 1) * 8] : receiver 1738 // -- rsp[(argc + 1) * 8] : receiver
1509 // ----------------------------------- 1739 // -----------------------------------
1510 1740
1511 // If object is not a string, bail out to regular call. 1741 // If object is not a string, bail out to regular call.
1512 if (!object->IsString() || cell != NULL) return Heap::undefined_value(); 1742 if (!object->IsString() || cell != NULL) return Heap::undefined_value();
1513 1743
1514 const int argc = arguments().immediate(); 1744 const int argc = arguments().immediate();
1515 1745
1516 Label miss; 1746 Label miss;
1517 Label index_out_of_range; 1747 Label index_out_of_range;
1748
1518 GenerateNameCheck(name, &miss); 1749 GenerateNameCheck(name, &miss);
1519 1750
1520 // Check that the maps starting from the prototype haven't changed. 1751 // Check that the maps starting from the prototype haven't changed.
1521 GenerateDirectLoadGlobalFunctionPrototype(masm(), 1752 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1522 Context::STRING_FUNCTION_INDEX, 1753 Context::STRING_FUNCTION_INDEX,
1523 rax, 1754 rax,
1524 &miss); 1755 &miss);
1525 ASSERT(object != holder); 1756 ASSERT(object != holder);
1526 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, 1757 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
1527 rbx, rdx, rdi, name, &miss); 1758 rbx, rdx, rdi, name, &miss);
1528 1759
1529 Register receiver = rbx; 1760 Register receiver = rax;
1530 Register index = rdi; 1761 Register index = rdi;
1531 Register scratch = rdx; 1762 Register scratch1 = rbx;
1763 Register scratch2 = rdx;
1532 Register result = rax; 1764 Register result = rax;
1533 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize)); 1765 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
1534 if (argc > 0) { 1766 if (argc > 0) {
1535 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize)); 1767 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
1536 } else { 1768 } else {
1537 __ LoadRoot(index, Heap::kUndefinedValueRootIndex); 1769 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1538 } 1770 }
1539 1771
1540 StringCharCodeAtGenerator char_code_at_generator(receiver, 1772 StringCharAtGenerator char_at_generator(receiver,
1541 index, 1773 index,
1542 scratch, 1774 scratch1,
1543 result, 1775 scratch2,
1544 &miss, // When not a string. 1776 result,
1545 &miss, // When not a number. 1777 &miss, // When not a string.
1546 &index_out_of_range, 1778 &miss, // When not a number.
1547 STRING_INDEX_IS_NUMBER); 1779 &index_out_of_range,
1548 char_code_at_generator.GenerateFast(masm()); 1780 STRING_INDEX_IS_NUMBER);
1781 char_at_generator.GenerateFast(masm());
1549 __ ret((argc + 1) * kPointerSize); 1782 __ ret((argc + 1) * kPointerSize);
1550 1783
1551 StubRuntimeCallHelper call_helper; 1784 StubRuntimeCallHelper call_helper;
1552 char_code_at_generator.GenerateSlow(masm(), call_helper); 1785 char_at_generator.GenerateSlow(masm(), call_helper);
1553 1786
1554 __ bind(&index_out_of_range); 1787 __ bind(&index_out_of_range);
1555 __ LoadRoot(rax, Heap::kNanValueRootIndex); 1788 __ LoadRoot(rax, Heap::kEmptyStringRootIndex);
1556 __ ret((argc + 1) * kPointerSize); 1789 __ ret((argc + 1) * kPointerSize);
1557 1790
1558 __ bind(&miss); 1791 __ bind(&miss);
1559 Object* obj; 1792 Object* obj;
1560 { MaybeObject* maybe_obj = GenerateMissBranch(); 1793 { MaybeObject* maybe_obj = GenerateMissBranch();
1561 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1794 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1562 } 1795 }
1563 1796
1564 // Return the generated code. 1797 // Return the generated code.
1565 return GetCode(function); 1798 return GetCode(function);
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
1745 Object* obj; 1978 Object* obj;
1746 { MaybeObject* maybe_obj = GenerateMissBranch(); 1979 { MaybeObject* maybe_obj = GenerateMissBranch();
1747 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1980 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1748 } 1981 }
1749 1982
1750 // Return the generated code. 1983 // Return the generated code.
1751 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); 1984 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
1752 } 1985 }
1753 1986
1754 1987
1988 MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
1989 JSObject* holder,
1990 JSFunction* function,
1991 String* name,
1992 CheckType check) {
1993 // ----------- S t a t e -------------
1994 // rcx : function name
1995 // rsp[0] : return address
1996 // rsp[8] : argument argc
1997 // rsp[16] : argument argc - 1
1998 // ...
1999 // rsp[argc * 8] : argument 1
2000 // rsp[(argc + 1) * 8] : argument 0 = receiver
2001 // -----------------------------------
2002
2003 SharedFunctionInfo* function_info = function->shared();
2004 if (function_info->HasBuiltinFunctionId()) {
2005 BuiltinFunctionId id = function_info->builtin_function_id();
2006 MaybeObject* maybe_result = CompileCustomCall(
2007 id, object, holder, NULL, function, name);
2008 Object* result;
2009 if (!maybe_result->ToObject(&result)) return maybe_result;
2010 // undefined means bail out to regular compiler.
2011 if (!result->IsUndefined()) return result;
2012 }
2013
2014 Label miss_in_smi_check;
2015
2016 GenerateNameCheck(name, &miss_in_smi_check);
2017
2018 // Get the receiver from the stack.
2019 const int argc = arguments().immediate();
2020 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
2021
2022 // Check that the receiver isn't a smi.
2023 if (check != NUMBER_CHECK) {
2024 __ JumpIfSmi(rdx, &miss_in_smi_check);
2025 }
2026
2027 // Make sure that it's okay not to patch the on stack receiver
2028 // unless we're doing a receiver map check.
2029 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
2030
2031 CallOptimization optimization(function);
2032 int depth = kInvalidProtoDepth;
2033 Label miss;
2034
2035 switch (check) {
2036 case RECEIVER_MAP_CHECK:
2037 __ IncrementCounter(&Counters::call_const, 1);
2038
2039 if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
2040 depth = optimization.GetPrototypeDepthOfExpectedType(
2041 JSObject::cast(object), holder);
2042 }
2043
2044 if (depth != kInvalidProtoDepth) {
2045 __ IncrementCounter(&Counters::call_const_fast_api, 1);
2046
2047 // Allocate space for v8::Arguments implicit values. Must be initialized
2048 // before to call any runtime function.
2049 __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
2050 }
2051
2052 // Check that the maps haven't changed.
2053 CheckPrototypes(JSObject::cast(object), rdx, holder,
2054 rbx, rax, rdi, name, depth, &miss);
2055
2056 // Patch the receiver on the stack with the global proxy if
2057 // necessary.
2058 if (object->IsGlobalObject()) {
2059 ASSERT(depth == kInvalidProtoDepth);
2060 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
2061 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
2062 }
2063 break;
2064
2065 case STRING_CHECK:
2066 if (!function->IsBuiltin()) {
2067 // Calling non-builtins with a value as receiver requires boxing.
2068 __ jmp(&miss);
2069 } else {
2070 // Check that the object is a two-byte string or a symbol.
2071 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax);
2072 __ j(above_equal, &miss);
2073 // Check that the maps starting from the prototype haven't changed.
2074 GenerateDirectLoadGlobalFunctionPrototype(
2075 masm(), Context::STRING_FUNCTION_INDEX, rax, &miss);
2076 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
2077 rbx, rdx, rdi, name, &miss);
2078 }
2079 break;
2080
2081 case NUMBER_CHECK: {
2082 if (!function->IsBuiltin()) {
2083 // Calling non-builtins with a value as receiver requires boxing.
2084 __ jmp(&miss);
2085 } else {
2086 Label fast;
2087 // Check that the object is a smi or a heap number.
2088 __ JumpIfSmi(rdx, &fast);
2089 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax);
2090 __ j(not_equal, &miss);
2091 __ bind(&fast);
2092 // Check that the maps starting from the prototype haven't changed.
2093 GenerateDirectLoadGlobalFunctionPrototype(
2094 masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss);
2095 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
2096 rbx, rdx, rdi, name, &miss);
2097 }
2098 break;
2099 }
2100
2101 case BOOLEAN_CHECK: {
2102 if (!function->IsBuiltin()) {
2103 // Calling non-builtins with a value as receiver requires boxing.
2104 __ jmp(&miss);
2105 } else {
2106 Label fast;
2107 // Check that the object is a boolean.
2108 __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
2109 __ j(equal, &fast);
2110 __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
2111 __ j(not_equal, &miss);
2112 __ bind(&fast);
2113 // Check that the maps starting from the prototype haven't changed.
2114 GenerateDirectLoadGlobalFunctionPrototype(
2115 masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss);
2116 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
2117 rbx, rdx, rdi, name, &miss);
2118 }
2119 break;
2120 }
2121
2122 default:
2123 UNREACHABLE();
2124 }
2125
2126 if (depth != kInvalidProtoDepth) {
2127 Failure* failure;
2128 // Move the return address on top of the stack.
2129 __ movq(rax, Operand(rsp, 3 * kPointerSize));
2130 __ movq(Operand(rsp, 0 * kPointerSize), rax);
2131
2132 // rsp[2 * kPointerSize] is uninitialized, rsp[3 * kPointerSize] contains
2133 // duplicate of return address and will be overwritten.
2134 bool success = GenerateFastApiCall(masm(), optimization, argc, &failure);
2135 if (!success) {
2136 return failure;
2137 }
2138 } else {
2139 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
2140 }
2141
2142 // Handle call cache miss.
2143 __ bind(&miss);
2144 if (depth != kInvalidProtoDepth) {
2145 __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
2146 }
2147
2148 // Handle call cache miss.
2149 __ bind(&miss_in_smi_check);
2150 Object* obj;
2151 { MaybeObject* maybe_obj = GenerateMissBranch();
2152 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2153 }
2154
2155 // Return the generated code.
2156 return GetCode(function);
2157 }
2158
2159
1755 MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, 2160 MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
1756 JSObject* holder, 2161 JSObject* holder,
1757 String* name) { 2162 String* name) {
1758 // ----------- S t a t e ------------- 2163 // ----------- S t a t e -------------
1759 // rcx : function name 2164 // rcx : function name
1760 // rsp[0] : return address 2165 // rsp[0] : return address
1761 // rsp[8] : argument argc 2166 // rsp[8] : argument argc
1762 // rsp[16] : argument argc - 1 2167 // rsp[16] : argument argc - 1
1763 // ... 2168 // ...
1764 // rsp[argc * 8] : argument 1 2169 // rsp[argc * 8] : argument 1
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
1885 Object* obj; 2290 Object* obj;
1886 { MaybeObject* maybe_obj = GenerateMissBranch(); 2291 { MaybeObject* maybe_obj = GenerateMissBranch();
1887 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 2292 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1888 } 2293 }
1889 2294
1890 // Return the generated code. 2295 // Return the generated code.
1891 return GetCode(NORMAL, name); 2296 return GetCode(NORMAL, name);
1892 } 2297 }
1893 2298
1894 2299
1895 MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name, 2300 MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object,
1896 JSObject* object, 2301 int index,
1897 JSObject* holder, 2302 Map* transition,
1898 AccessorInfo* callback) { 2303 String* name) {
1899 // ----------- S t a t e ------------- 2304 // ----------- S t a t e -------------
1900 // -- rax : receiver 2305 // -- rax : value
1901 // -- rcx : name 2306 // -- rcx : name
1902 // -- rsp[0] : return address 2307 // -- rdx : receiver
1903 // ----------------------------------- 2308 // -- rsp[0] : return address
1904 Label miss; 2309 // -----------------------------------
1905 2310 Label miss;
1906 Failure* failure = Failure::InternalError(); 2311
1907 bool success = GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx, rdi, 2312 // Generate store field code. Preserves receiver and name on jump to miss.
1908 callback, name, &miss, &failure); 2313 GenerateStoreField(masm(),
1909 if (!success) { 2314 object,
1910 miss.Unuse(); 2315 index,
1911 return failure; 2316 transition,
2317 rdx, rcx, rbx,
2318 &miss);
2319
2320 // Handle store cache miss.
2321 __ bind(&miss);
2322 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2323 __ Jump(ic, RelocInfo::CODE_TARGET);
2324
2325 // Return the generated code.
2326 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2327 }
2328
2329
2330 MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
2331 AccessorInfo* callback,
2332 String* name) {
2333 // ----------- S t a t e -------------
2334 // -- rax : value
2335 // -- rcx : name
2336 // -- rdx : receiver
2337 // -- rsp[0] : return address
2338 // -----------------------------------
2339 Label miss;
2340
2341 // Check that the object isn't a smi.
2342 __ JumpIfSmi(rdx, &miss);
2343
2344 // Check that the map of the object hasn't changed.
2345 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
2346 Handle<Map>(object->map()));
2347 __ j(not_equal, &miss);
2348
2349 // Perform global security token check if needed.
2350 if (object->IsJSGlobalProxy()) {
2351 __ CheckAccessGlobalProxy(rdx, rbx, &miss);
1912 } 2352 }
1913 2353
1914 __ bind(&miss); 2354 // Stub never generated for non-global objects that require access
1915 GenerateLoadMiss(masm(), Code::LOAD_IC); 2355 // checks.
2356 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2357
2358 __ pop(rbx); // remove the return address
2359 __ push(rdx); // receiver
2360 __ Push(Handle<AccessorInfo>(callback)); // callback info
2361 __ push(rcx); // name
2362 __ push(rax); // value
2363 __ push(rbx); // restore return address
2364
2365 // Do tail-call to the runtime system.
2366 ExternalReference store_callback_property =
2367 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
2368 __ TailCallExternalReference(store_callback_property, 4, 1);
2369
2370 // Handle store cache miss.
2371 __ bind(&miss);
2372 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2373 __ Jump(ic, RelocInfo::CODE_TARGET);
1916 2374
1917 // Return the generated code. 2375 // Return the generated code.
1918 return GetCode(CALLBACKS, name); 2376 return GetCode(CALLBACKS, name);
1919 } 2377 }
1920 2378
1921 2379
1922 MaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object, 2380 MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1923 JSObject* holder, 2381 String* name) {
1924 Object* value, 2382 // ----------- S t a t e -------------
2383 // -- rax : value
2384 // -- rcx : name
2385 // -- rdx : receiver
2386 // -- rsp[0] : return address
2387 // -----------------------------------
2388 Label miss;
2389
2390 // Check that the object isn't a smi.
2391 __ JumpIfSmi(rdx, &miss);
2392
2393 // Check that the map of the object hasn't changed.
2394 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
2395 Handle<Map>(receiver->map()));
2396 __ j(not_equal, &miss);
2397
2398 // Perform global security token check if needed.
2399 if (receiver->IsJSGlobalProxy()) {
2400 __ CheckAccessGlobalProxy(rdx, rbx, &miss);
2401 }
2402
2403 // Stub never generated for non-global objects that require access
2404 // checks.
2405 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2406
2407 __ pop(rbx); // remove the return address
2408 __ push(rdx); // receiver
2409 __ push(rcx); // name
2410 __ push(rax); // value
2411 __ push(rbx); // restore return address
2412
2413 // Do tail-call to the runtime system.
2414 ExternalReference store_ic_property =
2415 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
2416 __ TailCallExternalReference(store_ic_property, 3, 1);
2417
2418 // Handle store cache miss.
2419 __ bind(&miss);
2420 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2421 __ Jump(ic, RelocInfo::CODE_TARGET);
2422
2423 // Return the generated code.
2424 return GetCode(INTERCEPTOR, name);
2425 }
2426
2427
2428 MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
2429 JSGlobalPropertyCell* cell,
1925 String* name) { 2430 String* name) {
1926 // ----------- S t a t e ------------- 2431 // ----------- S t a t e -------------
1927 // -- rax : receiver 2432 // -- rax : value
1928 // -- rcx : name 2433 // -- rcx : name
1929 // -- rsp[0] : return address 2434 // -- rdx : receiver
1930 // ----------------------------------- 2435 // -- rsp[0] : return address
1931 Label miss; 2436 // -----------------------------------
1932 2437 Label miss;
1933 GenerateLoadConstant(object, holder, rax, rbx, rdx, rdi, value, name, &miss); 2438
1934 __ bind(&miss); 2439 // Check that the map of the global has not changed.
1935 GenerateLoadMiss(masm(), Code::LOAD_IC); 2440 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
1936 2441 Handle<Map>(object->map()));
1937 // Return the generated code. 2442 __ j(not_equal, &miss);
1938 return GetCode(CONSTANT_FUNCTION, name); 2443
2444 // Store the value in the cell.
2445 __ Move(rcx, Handle<JSGlobalPropertyCell>(cell));
2446 __ movq(FieldOperand(rcx, JSGlobalPropertyCell::kValueOffset), rax);
2447
2448 // Return the value (register rax).
2449 __ IncrementCounter(&Counters::named_store_global_inline, 1);
2450 __ ret(0);
2451
2452 // Handle store cache miss.
2453 __ bind(&miss);
2454 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1);
2455 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2456 __ Jump(ic, RelocInfo::CODE_TARGET);
2457
2458 // Return the generated code.
2459 return GetCode(NORMAL, name);
2460 }
2461
2462
2463 MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
2464 int index,
2465 Map* transition,
2466 String* name) {
2467 // ----------- S t a t e -------------
2468 // -- rax : value
2469 // -- rcx : key
2470 // -- rdx : receiver
2471 // -- rsp[0] : return address
2472 // -----------------------------------
2473 Label miss;
2474
2475 __ IncrementCounter(&Counters::keyed_store_field, 1);
2476
2477 // Check that the name has not changed.
2478 __ Cmp(rcx, Handle<String>(name));
2479 __ j(not_equal, &miss);
2480
2481 // Generate store field code. Preserves receiver and name on jump to miss.
2482 GenerateStoreField(masm(),
2483 object,
2484 index,
2485 transition,
2486 rdx, rcx, rbx,
2487 &miss);
2488
2489 // Handle store cache miss.
2490 __ bind(&miss);
2491 __ DecrementCounter(&Counters::keyed_store_field, 1);
2492 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
2493 __ Jump(ic, RelocInfo::CODE_TARGET);
2494
2495 // Return the generated code.
2496 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2497 }
2498
2499
2500 MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
2501 JSObject* receiver) {
2502 // ----------- S t a t e -------------
2503 // -- rax : value
2504 // -- rcx : key
2505 // -- rdx : receiver
2506 // -- rsp[0] : return address
2507 // -----------------------------------
2508 Label miss;
2509
2510 // Check that the receiver isn't a smi.
2511 __ JumpIfSmi(rdx, &miss);
2512
2513 // Check that the map matches.
2514 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
2515 Handle<Map>(receiver->map()));
2516 __ j(not_equal, &miss);
2517
2518 // Check that the key is a smi.
2519 __ JumpIfNotSmi(rcx, &miss);
2520
2521 // Get the elements array and make sure it is a fast element array, not 'cow'.
2522 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
2523 __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset),
2524 Factory::fixed_array_map());
2525 __ j(not_equal, &miss);
2526
2527 // Check that the key is within bounds.
2528 if (receiver->IsJSArray()) {
2529 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
2530 __ j(above_equal, &miss);
2531 } else {
2532 __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
2533 __ j(above_equal, &miss);
2534 }
2535
2536 // Do the store and update the write barrier. Make sure to preserve
2537 // the value in register eax.
2538 __ movq(rdx, rax);
2539 __ SmiToInteger32(rcx, rcx);
2540 __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize),
2541 rax);
2542 #ifdef ENABLE_CARDMARKING_WRITE_BARRIER
2543 __ RecordWrite(rdi, 0, rdx, rcx);
2544 #endif
2545
2546 // Done.
2547 __ ret(0);
2548
2549 // Handle store cache miss.
2550 __ bind(&miss);
2551 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
2552 __ jmp(ic, RelocInfo::CODE_TARGET);
2553
2554 // Return the generated code.
2555 return GetCode(NORMAL, NULL);
1939 } 2556 }
1940 2557
1941 2558
1942 MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, 2559 MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
1943 JSObject* object, 2560 JSObject* object,
1944 JSObject* last) { 2561 JSObject* last) {
1945 // ----------- S t a t e ------------- 2562 // ----------- S t a t e -------------
1946 // -- rax : receiver 2563 // -- rax : receiver
1947 // -- rcx : name 2564 // -- rcx : name
1948 // -- rsp[0] : return address 2565 // -- rsp[0] : return address
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
1997 2614
1998 GenerateLoadField(object, holder, rax, rbx, rdx, rdi, index, name, &miss); 2615 GenerateLoadField(object, holder, rax, rbx, rdx, rdi, index, name, &miss);
1999 __ bind(&miss); 2616 __ bind(&miss);
2000 GenerateLoadMiss(masm(), Code::LOAD_IC); 2617 GenerateLoadMiss(masm(), Code::LOAD_IC);
2001 2618
2002 // Return the generated code. 2619 // Return the generated code.
2003 return GetCode(FIELD, name); 2620 return GetCode(FIELD, name);
2004 } 2621 }
2005 2622
2006 2623
2624 MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name,
2625 JSObject* object,
2626 JSObject* holder,
2627 AccessorInfo* callback) {
2628 // ----------- S t a t e -------------
2629 // -- rax : receiver
2630 // -- rcx : name
2631 // -- rsp[0] : return address
2632 // -----------------------------------
2633 Label miss;
2634
2635 Failure* failure = Failure::InternalError();
2636 bool success = GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx, rdi,
2637 callback, name, &miss, &failure);
2638 if (!success) {
2639 miss.Unuse();
2640 return failure;
2641 }
2642
2643 __ bind(&miss);
2644 GenerateLoadMiss(masm(), Code::LOAD_IC);
2645
2646 // Return the generated code.
2647 return GetCode(CALLBACKS, name);
2648 }
2649
2650
2651 MaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object,
2652 JSObject* holder,
2653 Object* value,
2654 String* name) {
2655 // ----------- S t a t e -------------
2656 // -- rax : receiver
2657 // -- rcx : name
2658 // -- rsp[0] : return address
2659 // -----------------------------------
2660 Label miss;
2661
2662 GenerateLoadConstant(object, holder, rax, rbx, rdx, rdi, value, name, &miss);
2663 __ bind(&miss);
2664 GenerateLoadMiss(masm(), Code::LOAD_IC);
2665
2666 // Return the generated code.
2667 return GetCode(CONSTANT_FUNCTION, name);
2668 }
2669
2670
2007 MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, 2671 MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
2008 JSObject* holder, 2672 JSObject* holder,
2009 String* name) { 2673 String* name) {
2010 // ----------- S t a t e ------------- 2674 // ----------- S t a t e -------------
2011 // -- rax : receiver 2675 // -- rax : receiver
2012 // -- rcx : name 2676 // -- rcx : name
2013 // -- rsp[0] : return address 2677 // -- rsp[0] : return address
2014 // ----------------------------------- 2678 // -----------------------------------
2015 Label miss; 2679 Label miss;
2016 2680
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
2079 2743
2080 __ bind(&miss); 2744 __ bind(&miss);
2081 __ IncrementCounter(&Counters::named_load_global_stub_miss, 1); 2745 __ IncrementCounter(&Counters::named_load_global_stub_miss, 1);
2082 GenerateLoadMiss(masm(), Code::LOAD_IC); 2746 GenerateLoadMiss(masm(), Code::LOAD_IC);
2083 2747
2084 // Return the generated code. 2748 // Return the generated code.
2085 return GetCode(NORMAL, name); 2749 return GetCode(NORMAL, name);
2086 } 2750 }
2087 2751
2088 2752
2089 MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( 2753 MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
2090 String* name, 2754 JSObject* receiver,
2091 JSObject* receiver, 2755 JSObject* holder,
2092 JSObject* holder, 2756 int index) {
2093 AccessorInfo* callback) {
2094 // ----------- S t a t e ------------- 2757 // ----------- S t a t e -------------
2095 // -- rax : key 2758 // -- rax : key
2096 // -- rdx : receiver 2759 // -- rdx : receiver
2097 // -- rsp[0] : return address 2760 // -- rsp[0] : return address
2098 // ----------------------------------- 2761 // -----------------------------------
2099 Label miss; 2762 Label miss;
2100 2763
2764 __ IncrementCounter(&Counters::keyed_load_field, 1);
2765
2766 // Check that the name has not changed.
2767 __ Cmp(rax, Handle<String>(name));
2768 __ j(not_equal, &miss);
2769
2770 GenerateLoadField(receiver, holder, rdx, rbx, rcx, rdi, index, name, &miss);
2771
2772 __ bind(&miss);
2773 __ DecrementCounter(&Counters::keyed_load_field, 1);
2774 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2775
2776 // Return the generated code.
2777 return GetCode(FIELD, name);
2778 }
2779
2780
2781 MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
2782 String* name,
2783 JSObject* receiver,
2784 JSObject* holder,
2785 AccessorInfo* callback) {
2786 // ----------- S t a t e -------------
2787 // -- rax : key
2788 // -- rdx : receiver
2789 // -- rsp[0] : return address
2790 // -----------------------------------
2791 Label miss;
2792
2101 __ IncrementCounter(&Counters::keyed_load_callback, 1); 2793 __ IncrementCounter(&Counters::keyed_load_callback, 1);
2102 2794
2103 // Check that the name has not changed. 2795 // Check that the name has not changed.
2104 __ Cmp(rax, Handle<String>(name)); 2796 __ Cmp(rax, Handle<String>(name));
2105 __ j(not_equal, &miss); 2797 __ j(not_equal, &miss);
2106 2798
2107 Failure* failure = Failure::InternalError(); 2799 Failure* failure = Failure::InternalError();
2108 bool success = GenerateLoadCallback(receiver, holder, rdx, rax, rbx, rcx, rdi, 2800 bool success = GenerateLoadCallback(receiver, holder, rdx, rax, rbx, rcx, rdi,
2109 callback, name, &miss, &failure); 2801 callback, name, &miss, &failure);
2110 if (!success) { 2802 if (!success) {
2111 miss.Unuse(); 2803 miss.Unuse();
2112 return failure; 2804 return failure;
2113 } 2805 }
2114 2806
2115 __ bind(&miss); 2807 __ bind(&miss);
2808
2116 __ DecrementCounter(&Counters::keyed_load_callback, 1); 2809 __ DecrementCounter(&Counters::keyed_load_callback, 1);
2117 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 2810 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2118 2811
2119 // Return the generated code. 2812 // Return the generated code.
2120 return GetCode(CALLBACKS, name);
2121 }
2122
2123
2124 MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
2125 // ----------- S t a t e -------------
2126 // -- rax : key
2127 // -- rdx : receiver
2128 // -- rsp[0] : return address
2129 // -----------------------------------
2130 Label miss;
2131
2132 __ IncrementCounter(&Counters::keyed_load_array_length, 1);
2133
2134 // Check that the name has not changed.
2135 __ Cmp(rax, Handle<String>(name));
2136 __ j(not_equal, &miss);
2137
2138 GenerateLoadArrayLength(masm(), rdx, rcx, &miss);
2139 __ bind(&miss);
2140 __ DecrementCounter(&Counters::keyed_load_array_length, 1);
2141 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2142
2143 // Return the generated code.
2144 return GetCode(CALLBACKS, name); 2813 return GetCode(CALLBACKS, name);
2145 } 2814 }
2146 2815
2147 2816
2148 MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name, 2817 MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
2149 JSObject* receiver, 2818 JSObject* receiver,
2150 JSObject* holder, 2819 JSObject* holder,
2151 Object* value) { 2820 Object* value) {
2152 // ----------- S t a t e ------------- 2821 // ----------- S t a t e -------------
2153 // -- rax : key 2822 // -- rax : key
(...skipping 12 matching lines...) Expand all
2166 value, name, &miss); 2835 value, name, &miss);
2167 __ bind(&miss); 2836 __ bind(&miss);
2168 __ DecrementCounter(&Counters::keyed_load_constant_function, 1); 2837 __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
2169 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 2838 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2170 2839
2171 // Return the generated code. 2840 // Return the generated code.
2172 return GetCode(CONSTANT_FUNCTION, name); 2841 return GetCode(CONSTANT_FUNCTION, name);
2173 } 2842 }
2174 2843
2175 2844
2176 MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
2177 // ----------- S t a t e -------------
2178 // -- rax : key
2179 // -- rdx : receiver
2180 // -- rsp[0] : return address
2181 // -----------------------------------
2182 Label miss;
2183
2184 __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
2185
2186 // Check that the name has not changed.
2187 __ Cmp(rax, Handle<String>(name));
2188 __ j(not_equal, &miss);
2189
2190 GenerateLoadFunctionPrototype(masm(), rdx, rcx, rbx, &miss);
2191 __ bind(&miss);
2192 __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
2193 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2194
2195 // Return the generated code.
2196 return GetCode(CALLBACKS, name);
2197 }
2198
2199
2200 MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, 2845 MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
2201 JSObject* holder, 2846 JSObject* holder,
2202 String* name) { 2847 String* name) {
2203 // ----------- S t a t e ------------- 2848 // ----------- S t a t e -------------
2204 // -- rax : key 2849 // -- rax : key
2205 // -- rdx : receiver 2850 // -- rdx : receiver
2206 // -- rsp[0] : return address 2851 // -- rsp[0] : return address
2207 // ----------------------------------- 2852 // -----------------------------------
2208 Label miss; 2853 Label miss;
2209 2854
(...skipping 17 matching lines...) Expand all
2227 &miss); 2872 &miss);
2228 __ bind(&miss); 2873 __ bind(&miss);
2229 __ DecrementCounter(&Counters::keyed_load_interceptor, 1); 2874 __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
2230 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 2875 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2231 2876
2232 // Return the generated code. 2877 // Return the generated code.
2233 return GetCode(INTERCEPTOR, name); 2878 return GetCode(INTERCEPTOR, name);
2234 } 2879 }
2235 2880
2236 2881
2237 MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { 2882 MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
2238 // ----------- S t a t e ------------- 2883 // ----------- S t a t e -------------
2239 // -- rax : key 2884 // -- rax : key
2240 // -- rdx : receiver 2885 // -- rdx : receiver
2241 // -- rsp[0] : return address 2886 // -- rsp[0] : return address
2242 // ----------------------------------- 2887 // -----------------------------------
2243 Label miss; 2888 Label miss;
2244 2889
2245 __ IncrementCounter(&Counters::keyed_load_string_length, 1); 2890 __ IncrementCounter(&Counters::keyed_load_array_length, 1);
2246 2891
2247 // Check that the name has not changed. 2892 // Check that the name has not changed.
2248 __ Cmp(rax, Handle<String>(name)); 2893 __ Cmp(rax, Handle<String>(name));
2249 __ j(not_equal, &miss); 2894 __ j(not_equal, &miss);
2250 2895
2251 GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss); 2896 GenerateLoadArrayLength(masm(), rdx, rcx, &miss);
2252 __ bind(&miss); 2897 __ bind(&miss);
2253 __ DecrementCounter(&Counters::keyed_load_string_length, 1); 2898 __ DecrementCounter(&Counters::keyed_load_array_length, 1);
2254 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 2899 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2255 2900
2256 // Return the generated code. 2901 // Return the generated code.
2257 return GetCode(CALLBACKS, name); 2902 return GetCode(CALLBACKS, name);
2258 } 2903 }
2259 2904
2260 2905
2906 MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
2907 // ----------- S t a t e -------------
2908 // -- rax : key
2909 // -- rdx : receiver
2910 // -- rsp[0] : return address
2911 // -----------------------------------
2912 Label miss;
2913
2914 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
2915
2916 // Check that the name has not changed.
2917 __ Cmp(rax, Handle<String>(name));
2918 __ j(not_equal, &miss);
2919
2920 GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss);
2921 __ bind(&miss);
2922 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
2923 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2924
2925 // Return the generated code.
2926 return GetCode(CALLBACKS, name);
2927 }
2928
2929
2930 MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
2931 // ----------- S t a t e -------------
2932 // -- rax : key
2933 // -- rdx : receiver
2934 // -- rsp[0] : return address
2935 // -----------------------------------
2936 Label miss;
2937
2938 __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
2939
2940 // Check that the name has not changed.
2941 __ Cmp(rax, Handle<String>(name));
2942 __ j(not_equal, &miss);
2943
2944 GenerateLoadFunctionPrototype(masm(), rdx, rcx, rbx, &miss);
2945 __ bind(&miss);
2946 __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
2947 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2948
2949 // Return the generated code.
2950 return GetCode(CALLBACKS, name);
2951 }
2952
2953
2261 MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) { 2954 MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
2262 // ----------- S t a t e ------------- 2955 // ----------- S t a t e -------------
2263 // -- rax : key 2956 // -- rax : key
2264 // -- rdx : receiver 2957 // -- rdx : receiver
2265 // -- esp[0] : return address 2958 // -- esp[0] : return address
2266 // ----------------------------------- 2959 // -----------------------------------
2267 Label miss; 2960 Label miss;
2268 2961
2269 // Check that the receiver isn't a smi.
2270 __ JumpIfSmi(rdx, &miss);
2271
2272 // Check that the map matches.
2273 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
2274 Handle<Map>(receiver->map()));
2275 __ j(not_equal, &miss);
2276
2277 // Check that the key is a smi.
2278 __ JumpIfNotSmi(rax, &miss);
2279
2280 // Get the elements array.
2281 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
2282 __ AssertFastElements(rcx);
2283
2284 // Check that the key is within bounds.
2285 __ SmiCompare(rax, FieldOperand(rcx, FixedArray::kLengthOffset));
2286 __ j(above_equal, &miss);
2287
2288 // Load the result and make sure it's not the hole.
2289 SmiIndex index = masm()->SmiToIndex(rbx, rax, kPointerSizeLog2);
2290 __ movq(rbx, FieldOperand(rcx,
2291 index.reg,
2292 index.scale,
2293 FixedArray::kHeaderSize));
2294 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
2295 __ j(equal, &miss);
2296 __ movq(rax, rbx);
2297 __ ret(0);
2298
2299 __ bind(&miss);
2300 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2301
2302 // Return the generated code.
2303 return GetCode(NORMAL, NULL);
2304 }
2305
2306
2307 MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
2308 AccessorInfo* callback,
2309 String* name) {
2310 // ----------- S t a t e -------------
2311 // -- rax : value
2312 // -- rcx : name
2313 // -- rdx : receiver
2314 // -- rsp[0] : return address
2315 // -----------------------------------
2316 Label miss;
2317
2318 // Check that the object isn't a smi.
2319 __ JumpIfSmi(rdx, &miss);
2320
2321 // Check that the map of the object hasn't changed.
2322 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
2323 Handle<Map>(object->map()));
2324 __ j(not_equal, &miss);
2325
2326 // Perform global security token check if needed.
2327 if (object->IsJSGlobalProxy()) {
2328 __ CheckAccessGlobalProxy(rdx, rbx, &miss);
2329 }
2330
2331 // Stub never generated for non-global objects that require access
2332 // checks.
2333 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2334
2335 __ pop(rbx); // remove the return address
2336 __ push(rdx); // receiver
2337 __ Push(Handle<AccessorInfo>(callback)); // callback info
2338 __ push(rcx); // name
2339 __ push(rax); // value
2340 __ push(rbx); // restore return address
2341
2342 // Do tail-call to the runtime system.
2343 ExternalReference store_callback_property =
2344 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
2345 __ TailCallExternalReference(store_callback_property, 4, 1);
2346
2347 // Handle store cache miss.
2348 __ bind(&miss);
2349 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2350 __ Jump(ic, RelocInfo::CODE_TARGET);
2351
2352 // Return the generated code.
2353 return GetCode(CALLBACKS, name);
2354 }
2355
2356
2357 MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object,
2358 int index,
2359 Map* transition,
2360 String* name) {
2361 // ----------- S t a t e -------------
2362 // -- rax : value
2363 // -- rcx : name
2364 // -- rdx : receiver
2365 // -- rsp[0] : return address
2366 // -----------------------------------
2367 Label miss;
2368
2369 // Generate store field code. Preserves receiver and name on jump to miss.
2370 GenerateStoreField(masm(),
2371 object,
2372 index,
2373 transition,
2374 rdx, rcx, rbx,
2375 &miss);
2376
2377 // Handle store cache miss.
2378 __ bind(&miss);
2379 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2380 __ Jump(ic, RelocInfo::CODE_TARGET);
2381
2382 // Return the generated code.
2383 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2384 }
2385
2386
2387 MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
2388 String* name) {
2389 // ----------- S t a t e -------------
2390 // -- rax : value
2391 // -- rcx : name
2392 // -- rdx : receiver
2393 // -- rsp[0] : return address
2394 // -----------------------------------
2395 Label miss;
2396
2397 // Check that the object isn't a smi.
2398 __ JumpIfSmi(rdx, &miss);
2399
2400 // Check that the map of the object hasn't changed.
2401 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
2402 Handle<Map>(receiver->map()));
2403 __ j(not_equal, &miss);
2404
2405 // Perform global security token check if needed.
2406 if (receiver->IsJSGlobalProxy()) {
2407 __ CheckAccessGlobalProxy(rdx, rbx, &miss);
2408 }
2409
2410 // Stub never generated for non-global objects that require access
2411 // checks.
2412 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2413
2414 __ pop(rbx); // remove the return address
2415 __ push(rdx); // receiver
2416 __ push(rcx); // name
2417 __ push(rax); // value
2418 __ push(rbx); // restore return address
2419
2420 // Do tail-call to the runtime system.
2421 ExternalReference store_ic_property =
2422 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
2423 __ TailCallExternalReference(store_ic_property, 3, 1);
2424
2425 // Handle store cache miss.
2426 __ bind(&miss);
2427 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2428 __ Jump(ic, RelocInfo::CODE_TARGET);
2429
2430 // Return the generated code.
2431 return GetCode(INTERCEPTOR, name);
2432 }
2433
2434
2435 MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
2436 JSGlobalPropertyCell* cell,
2437 String* name) {
2438 // ----------- S t a t e -------------
2439 // -- rax : value
2440 // -- rcx : name
2441 // -- rdx : receiver
2442 // -- rsp[0] : return address
2443 // -----------------------------------
2444 Label miss;
2445
2446 // Check that the map of the global has not changed.
2447 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
2448 Handle<Map>(object->map()));
2449 __ j(not_equal, &miss);
2450
2451 // Store the value in the cell.
2452 __ Move(rcx, Handle<JSGlobalPropertyCell>(cell));
2453 __ movq(FieldOperand(rcx, JSGlobalPropertyCell::kValueOffset), rax);
2454
2455 // Return the value (register rax).
2456 __ IncrementCounter(&Counters::named_store_global_inline, 1);
2457 __ ret(0);
2458
2459 // Handle store cache miss.
2460 __ bind(&miss);
2461 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1);
2462 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
2463 __ Jump(ic, RelocInfo::CODE_TARGET);
2464
2465 // Return the generated code.
2466 return GetCode(NORMAL, name);
2467 }
2468
2469
2470 MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
2471 JSObject* receiver,
2472 JSObject* holder,
2473 int index) {
2474 // ----------- S t a t e -------------
2475 // -- rax : key
2476 // -- rdx : receiver
2477 // -- rsp[0] : return address
2478 // -----------------------------------
2479 Label miss;
2480
2481 __ IncrementCounter(&Counters::keyed_load_field, 1);
2482
2483 // Check that the name has not changed.
2484 __ Cmp(rax, Handle<String>(name));
2485 __ j(not_equal, &miss);
2486
2487 GenerateLoadField(receiver, holder, rdx, rbx, rcx, rdi, index, name, &miss);
2488
2489 __ bind(&miss);
2490 __ DecrementCounter(&Counters::keyed_load_field, 1);
2491 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2492
2493 // Return the generated code.
2494 return GetCode(FIELD, name);
2495 }
2496
2497
2498 MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
2499 int index,
2500 Map* transition,
2501 String* name) {
2502 // ----------- S t a t e -------------
2503 // -- rax : value
2504 // -- rcx : key
2505 // -- rdx : receiver
2506 // -- rsp[0] : return address
2507 // -----------------------------------
2508 Label miss;
2509
2510 __ IncrementCounter(&Counters::keyed_store_field, 1);
2511
2512 // Check that the name has not changed.
2513 __ Cmp(rcx, Handle<String>(name));
2514 __ j(not_equal, &miss);
2515
2516 // Generate store field code. Preserves receiver and name on jump to miss.
2517 GenerateStoreField(masm(),
2518 object,
2519 index,
2520 transition,
2521 rdx, rcx, rbx,
2522 &miss);
2523
2524 // Handle store cache miss.
2525 __ bind(&miss);
2526 __ DecrementCounter(&Counters::keyed_store_field, 1);
2527 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
2528 __ Jump(ic, RelocInfo::CODE_TARGET);
2529
2530 // Return the generated code.
2531 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
2532 }
2533
2534
2535 MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
2536 JSObject* receiver) {
2537 // ----------- S t a t e -------------
2538 // -- rax : value
2539 // -- rcx : key
2540 // -- rdx : receiver
2541 // -- rsp[0] : return address
2542 // -----------------------------------
2543 Label miss;
2544
2545 // Check that the receiver isn't a smi. 2962 // Check that the receiver isn't a smi.
2546 __ JumpIfSmi(rdx, &miss); 2963 __ JumpIfSmi(rdx, &miss);
2547 2964
2548 // Check that the map matches. 2965 // Check that the map matches.
2549 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), 2966 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
2550 Handle<Map>(receiver->map())); 2967 Handle<Map>(receiver->map()));
2551 __ j(not_equal, &miss); 2968 __ j(not_equal, &miss);
2552 2969
2553 // Check that the key is a smi. 2970 // Check that the key is a smi.
2554 __ JumpIfNotSmi(rcx, &miss); 2971 __ JumpIfNotSmi(rax, &miss);
2555 2972
2556 // Get the elements array and make sure it is a fast element array, not 'cow'. 2973 // Get the elements array.
2557 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); 2974 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
2558 __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset), 2975 __ AssertFastElements(rcx);
2559 Factory::fixed_array_map());
2560 __ j(not_equal, &miss);
2561 2976
2562 // Check that the key is within bounds. 2977 // Check that the key is within bounds.
2563 if (receiver->IsJSArray()) { 2978 __ SmiCompare(rax, FieldOperand(rcx, FixedArray::kLengthOffset));
2564 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); 2979 __ j(above_equal, &miss);
2565 __ j(above_equal, &miss);
2566 } else {
2567 __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset));
2568 __ j(above_equal, &miss);
2569 }
2570 2980
2571 // Do the store and update the write barrier. Make sure to preserve 2981 // Load the result and make sure it's not the hole.
2572 // the value in register eax. 2982 SmiIndex index = masm()->SmiToIndex(rbx, rax, kPointerSizeLog2);
2573 __ movq(rdx, rax); 2983 __ movq(rbx, FieldOperand(rcx,
2574 __ SmiToInteger32(rcx, rcx); 2984 index.reg,
2575 __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize), 2985 index.scale,
2576 rax); 2986 FixedArray::kHeaderSize));
2577 #ifdef ENABLE_CARDMARKING_WRITE_BARRIER 2987 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
2578 __ RecordWrite(rdi, 0, rdx, rcx); 2988 __ j(equal, &miss);
2579 #endif 2989 __ movq(rax, rbx);
2580
2581 // Done.
2582 __ ret(0); 2990 __ ret(0);
2583 2991
2584 // Handle store cache miss.
2585 __ bind(&miss); 2992 __ bind(&miss);
2586 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); 2993 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2587 __ jmp(ic, RelocInfo::CODE_TARGET);
2588 2994
2589 // Return the generated code. 2995 // Return the generated code.
2590 return GetCode(NORMAL, NULL); 2996 return GetCode(NORMAL, NULL);
2591 } 2997 }
2592 2998
2593 2999
2594 void StubCompiler::GenerateLoadInterceptor(JSObject* object,
2595 JSObject* interceptor_holder,
2596 LookupResult* lookup,
2597 Register receiver,
2598 Register name_reg,
2599 Register scratch1,
2600 Register scratch2,
2601 Register scratch3,
2602 String* name,
2603 Label* miss) {
2604 ASSERT(interceptor_holder->HasNamedInterceptor());
2605 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
2606
2607 // Check that the receiver isn't a smi.
2608 __ JumpIfSmi(receiver, miss);
2609
2610 // So far the most popular follow ups for interceptor loads are FIELD
2611 // and CALLBACKS, so inline only them, other cases may be added
2612 // later.
2613 bool compile_followup_inline = false;
2614 if (lookup->IsProperty() && lookup->IsCacheable()) {
2615 if (lookup->type() == FIELD) {
2616 compile_followup_inline = true;
2617 } else if (lookup->type() == CALLBACKS &&
2618 lookup->GetCallbackObject()->IsAccessorInfo() &&
2619 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
2620 compile_followup_inline = true;
2621 }
2622 }
2623
2624 if (compile_followup_inline) {
2625 // Compile the interceptor call, followed by inline code to load the
2626 // property from further up the prototype chain if the call fails.
2627 // Check that the maps haven't changed.
2628 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
2629 scratch1, scratch2, scratch3,
2630 name, miss);
2631 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
2632
2633 // Save necessary data before invoking an interceptor.
2634 // Requires a frame to make GC aware of pushed pointers.
2635 __ EnterInternalFrame();
2636
2637 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
2638 // CALLBACKS case needs a receiver to be passed into C++ callback.
2639 __ push(receiver);
2640 }
2641 __ push(holder_reg);
2642 __ push(name_reg);
2643
2644 // Invoke an interceptor. Note: map checks from receiver to
2645 // interceptor's holder has been compiled before (see a caller
2646 // of this method.)
2647 CompileCallLoadPropertyWithInterceptor(masm(),
2648 receiver,
2649 holder_reg,
2650 name_reg,
2651 interceptor_holder);
2652
2653 // Check if interceptor provided a value for property. If it's
2654 // the case, return immediately.
2655 Label interceptor_failed;
2656 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
2657 __ j(equal, &interceptor_failed);
2658 __ LeaveInternalFrame();
2659 __ ret(0);
2660
2661 __ bind(&interceptor_failed);
2662 __ pop(name_reg);
2663 __ pop(holder_reg);
2664 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
2665 __ pop(receiver);
2666 }
2667
2668 __ LeaveInternalFrame();
2669
2670 // Check that the maps from interceptor's holder to lookup's holder
2671 // haven't changed. And load lookup's holder into |holder| register.
2672 if (interceptor_holder != lookup->holder()) {
2673 holder_reg = CheckPrototypes(interceptor_holder,
2674 holder_reg,
2675 lookup->holder(),
2676 scratch1,
2677 scratch2,
2678 scratch3,
2679 name,
2680 miss);
2681 }
2682
2683 if (lookup->type() == FIELD) {
2684 // We found FIELD property in prototype chain of interceptor's holder.
2685 // Retrieve a field from field's holder.
2686 GenerateFastPropertyLoad(masm(), rax, holder_reg,
2687 lookup->holder(), lookup->GetFieldIndex());
2688 __ ret(0);
2689 } else {
2690 // We found CALLBACKS property in prototype chain of interceptor's
2691 // holder.
2692 ASSERT(lookup->type() == CALLBACKS);
2693 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
2694 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
2695 ASSERT(callback != NULL);
2696 ASSERT(callback->getter() != NULL);
2697
2698 // Tail call to runtime.
2699 // Important invariant in CALLBACKS case: the code above must be
2700 // structured to never clobber |receiver| register.
2701 __ pop(scratch2); // return address
2702 __ push(receiver);
2703 __ push(holder_reg);
2704 __ Move(holder_reg, Handle<AccessorInfo>(callback));
2705 __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
2706 __ push(holder_reg);
2707 __ push(name_reg);
2708 __ push(scratch2); // restore return address
2709
2710 ExternalReference ref =
2711 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
2712 __ TailCallExternalReference(ref, 5, 1);
2713 }
2714 } else { // !compile_followup_inline
2715 // Call the runtime system to load the interceptor.
2716 // Check that the maps haven't changed.
2717 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
2718 scratch1, scratch2, scratch3,
2719 name, miss);
2720 __ pop(scratch2); // save old return address
2721 PushInterceptorArguments(masm(), receiver, holder_reg,
2722 name_reg, interceptor_holder);
2723 __ push(scratch2); // restore old return address
2724
2725 ExternalReference ref = ExternalReference(
2726 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
2727 __ TailCallExternalReference(ref, 5, 1);
2728 }
2729 }
2730
2731
2732 bool StubCompiler::GenerateLoadCallback(JSObject* object,
2733 JSObject* holder,
2734 Register receiver,
2735 Register name_reg,
2736 Register scratch1,
2737 Register scratch2,
2738 Register scratch3,
2739 AccessorInfo* callback,
2740 String* name,
2741 Label* miss,
2742 Failure** failure) {
2743 // Check that the receiver isn't a smi.
2744 __ JumpIfSmi(receiver, miss);
2745
2746 // Check that the maps haven't changed.
2747 Register reg =
2748 CheckPrototypes(object, receiver, holder, scratch1,
2749 scratch2, scratch3, name, miss);
2750
2751 Handle<AccessorInfo> callback_handle(callback);
2752
2753 // Insert additional parameters into the stack frame above return address.
2754 ASSERT(!scratch2.is(reg));
2755 __ pop(scratch2); // Get return address to place it below.
2756
2757 __ push(receiver); // receiver
2758 __ push(reg); // holder
2759 if (Heap::InNewSpace(callback_handle->data())) {
2760 __ Move(scratch1, callback_handle);
2761 __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); // data
2762 } else {
2763 __ Push(Handle<Object>(callback_handle->data()));
2764 }
2765 __ push(name_reg); // name
2766 // Save a pointer to where we pushed the arguments pointer.
2767 // This will be passed as the const AccessorInfo& to the C++ callback.
2768
2769 #ifdef _WIN64
2770 // Win64 uses first register--rcx--for returned value.
2771 Register accessor_info_arg = r8;
2772 Register name_arg = rdx;
2773 #else
2774 Register accessor_info_arg = rsi;
2775 Register name_arg = rdi;
2776 #endif
2777
2778 ASSERT(!name_arg.is(scratch2));
2779 __ movq(name_arg, rsp);
2780 __ push(scratch2); // Restore return address.
2781
2782 // Do call through the api.
2783 Address getter_address = v8::ToCData<Address>(callback->getter());
2784 ApiFunction fun(getter_address);
2785
2786 // 3 elements array for v8::Agruments::values_ and handler for name.
2787 const int kStackSpace = 4;
2788
2789 // Allocate v8::AccessorInfo in non-GCed stack space.
2790 const int kArgStackSpace = 1;
2791
2792 __ PrepareCallApiFunction(kArgStackSpace);
2793 __ lea(rax, Operand(name_arg, 3 * kPointerSize));
2794
2795 // v8::AccessorInfo::args_.
2796 __ movq(StackSpaceOperand(0), rax);
2797
2798 // The context register (rsi) has been saved in PrepareCallApiFunction and
2799 // could be used to pass arguments.
2800 __ lea(accessor_info_arg, StackSpaceOperand(0));
2801
2802 // Emitting a stub call may try to allocate (if the code is not
2803 // already generated). Do not allow the assembler to perform a
2804 // garbage collection but instead return the allocation failure
2805 // object.
2806 MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace);
2807 if (result->IsFailure()) {
2808 *failure = Failure::cast(result);
2809 return false;
2810 }
2811 return true;
2812 }
2813
2814
2815 Register StubCompiler::CheckPrototypes(JSObject* object,
2816 Register object_reg,
2817 JSObject* holder,
2818 Register holder_reg,
2819 Register scratch1,
2820 Register scratch2,
2821 String* name,
2822 int save_at_depth,
2823 Label* miss) {
2824 // Make sure there's no overlap between holder and object registers.
2825 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
2826 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
2827 && !scratch2.is(scratch1));
2828
2829 // Keep track of the current object in register reg. On the first
2830 // iteration, reg is an alias for object_reg, on later iterations,
2831 // it is an alias for holder_reg.
2832 Register reg = object_reg;
2833 int depth = 0;
2834
2835 if (save_at_depth == depth) {
2836 __ movq(Operand(rsp, kPointerSize), object_reg);
2837 }
2838
2839 // Check the maps in the prototype chain.
2840 // Traverse the prototype chain from the object and do map checks.
2841 JSObject* current = object;
2842 while (current != holder) {
2843 depth++;
2844
2845 // Only global objects and objects that do not require access
2846 // checks are allowed in stubs.
2847 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
2848
2849 JSObject* prototype = JSObject::cast(current->GetPrototype());
2850 if (!current->HasFastProperties() &&
2851 !current->IsJSGlobalObject() &&
2852 !current->IsJSGlobalProxy()) {
2853 if (!name->IsSymbol()) {
2854 MaybeObject* lookup_result = Heap::LookupSymbol(name);
2855 if (lookup_result->IsFailure()) {
2856 set_failure(Failure::cast(lookup_result));
2857 return reg;
2858 } else {
2859 name = String::cast(lookup_result->ToObjectUnchecked());
2860 }
2861 }
2862 ASSERT(current->property_dictionary()->FindEntry(name) ==
2863 StringDictionary::kNotFound);
2864
2865 GenerateDictionaryNegativeLookup(masm(),
2866 miss,
2867 reg,
2868 name,
2869 scratch1,
2870 scratch2);
2871 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
2872 reg = holder_reg; // from now the object is in holder_reg
2873 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
2874 } else if (Heap::InNewSpace(prototype)) {
2875 // Get the map of the current object.
2876 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
2877 __ Cmp(scratch1, Handle<Map>(current->map()));
2878 // Branch on the result of the map check.
2879 __ j(not_equal, miss);
2880 // Check access rights to the global object. This has to happen
2881 // after the map check so that we know that the object is
2882 // actually a global object.
2883 if (current->IsJSGlobalProxy()) {
2884 __ CheckAccessGlobalProxy(reg, scratch1, miss);
2885
2886 // Restore scratch register to be the map of the object.
2887 // We load the prototype from the map in the scratch register.
2888 __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
2889 }
2890 // The prototype is in new space; we cannot store a reference
2891 // to it in the code. Load it from the map.
2892 reg = holder_reg; // from now the object is in holder_reg
2893 __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
2894
2895 } else {
2896 // Check the map of the current object.
2897 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset),
2898 Handle<Map>(current->map()));
2899 // Branch on the result of the map check.
2900 __ j(not_equal, miss);
2901 // Check access rights to the global object. This has to happen
2902 // after the map check so that we know that the object is
2903 // actually a global object.
2904 if (current->IsJSGlobalProxy()) {
2905 __ CheckAccessGlobalProxy(reg, scratch1, miss);
2906 }
2907 // The prototype is in old space; load it directly.
2908 reg = holder_reg; // from now the object is in holder_reg
2909 __ Move(reg, Handle<JSObject>(prototype));
2910 }
2911
2912 if (save_at_depth == depth) {
2913 __ movq(Operand(rsp, kPointerSize), reg);
2914 }
2915
2916 // Go to the next object in the prototype chain.
2917 current = prototype;
2918 }
2919
2920 // Check the holder map.
2921 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), Handle<Map>(holder->map()));
2922 __ j(not_equal, miss);
2923
2924 // Log the check depth.
2925 LOG(IntEvent("check-maps-depth", depth + 1));
2926
2927 // Perform security check for access to the global object and return
2928 // the holder register.
2929 ASSERT(current == holder);
2930 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
2931 if (current->IsJSGlobalProxy()) {
2932 __ CheckAccessGlobalProxy(reg, scratch1, miss);
2933 }
2934
2935 // If we've skipped any global objects, it's not enough to verify
2936 // that their maps haven't changed. We also need to check that the
2937 // property cell for the property is still empty.
2938 current = object;
2939 while (current != holder) {
2940 if (current->IsGlobalObject()) {
2941 MaybeObject* cell = GenerateCheckPropertyCell(masm(),
2942 GlobalObject::cast(current),
2943 name,
2944 scratch1,
2945 miss);
2946 if (cell->IsFailure()) {
2947 set_failure(Failure::cast(cell));
2948 return reg;
2949 }
2950 }
2951 current = JSObject::cast(current->GetPrototype());
2952 }
2953
2954 // Return the register containing the holder.
2955 return reg;
2956 }
2957
2958
2959 void StubCompiler::GenerateLoadField(JSObject* object,
2960 JSObject* holder,
2961 Register receiver,
2962 Register scratch1,
2963 Register scratch2,
2964 Register scratch3,
2965 int index,
2966 String* name,
2967 Label* miss) {
2968 // Check that the receiver isn't a smi.
2969 __ JumpIfSmi(receiver, miss);
2970
2971 // Check the prototype chain.
2972 Register reg =
2973 CheckPrototypes(object, receiver, holder,
2974 scratch1, scratch2, scratch3, name, miss);
2975
2976 // Get the value from the properties.
2977 GenerateFastPropertyLoad(masm(), rax, reg, holder, index);
2978 __ ret(0);
2979 }
2980
2981
2982 void StubCompiler::GenerateLoadConstant(JSObject* object,
2983 JSObject* holder,
2984 Register receiver,
2985 Register scratch1,
2986 Register scratch2,
2987 Register scratch3,
2988 Object* value,
2989 String* name,
2990 Label* miss) {
2991 // Check that the receiver isn't a smi.
2992 __ JumpIfSmi(receiver, miss);
2993
2994 // Check that the maps haven't changed.
2995 Register reg =
2996 CheckPrototypes(object, receiver, holder,
2997 scratch1, scratch2, scratch3, name, miss);
2998
2999 // Return the constant value.
3000 __ Move(rax, Handle<Object>(value));
3001 __ ret(0);
3002 }
3003
3004
3005 // Specialized stub for constructing objects from functions which only have only 3000 // Specialized stub for constructing objects from functions which only have only
3006 // simple assignments of the form this.x = ...; in their body. 3001 // simple assignments of the form this.x = ...; in their body.
3007 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { 3002 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
3008 // ----------- S t a t e ------------- 3003 // ----------- S t a t e -------------
3009 // -- rax : argc 3004 // -- rax : argc
3010 // -- rdi : constructor 3005 // -- rdi : constructor
3011 // -- rsp[0] : return address 3006 // -- rsp[0] : return address
3012 // -- rsp[4] : last argument 3007 // -- rsp[4] : last argument
3013 // ----------------------------------- 3008 // -----------------------------------
3014 Label generic_stub_call; 3009 Label generic_stub_call;
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
3131 // Return the generated code. 3126 // Return the generated code.
3132 return GetCode(); 3127 return GetCode();
3133 } 3128 }
3134 3129
3135 3130
3136 #undef __ 3131 #undef __
3137 3132
3138 } } // namespace v8::internal 3133 } } // namespace v8::internal
3139 3134
3140 #endif // V8_TARGET_ARCH_X64 3135 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/x64/regexp-macro-assembler-x64.cc ('k') | test/cctest/cctest.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698