OLD | NEW |
---|---|
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 |
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
293 Register holder, | 293 Register holder, |
294 Register name, | 294 Register name, |
295 JSObject* holder_obj) { | 295 JSObject* holder_obj) { |
296 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); | 296 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); |
297 __ CallExternalReference( | 297 __ CallExternalReference( |
298 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly)), | 298 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly)), |
299 5); | 299 5); |
300 } | 300 } |
301 | 301 |
302 | 302 |
303 template <class Compiler> | |
304 static void CompileLoadInterceptor(Compiler* compiler, | |
305 StubCompiler* stub_compiler, | |
306 MacroAssembler* masm, | |
307 JSObject* object, | |
308 JSObject* holder, | |
309 String* name, | |
310 LookupResult* lookup, | |
311 Register receiver, | |
312 Register scratch1, | |
313 Register scratch2, | |
314 Label* miss) { | |
315 ASSERT(holder->HasNamedInterceptor()); | |
316 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | |
317 | |
318 // Check that the receiver isn't a smi. | |
319 __ test(receiver, Immediate(kSmiTagMask)); | |
320 __ j(zero, miss, not_taken); | |
321 | |
322 // Check that the maps haven't changed. | |
323 Register reg = | |
324 stub_compiler->CheckPrototypes(object, receiver, holder, | |
325 scratch1, scratch2, name, miss); | |
326 | |
327 if (lookup->IsProperty() && lookup->IsCacheable()) { | |
328 compiler->CompileCacheable(masm, | |
329 stub_compiler, | |
330 receiver, | |
331 reg, | |
332 scratch1, | |
333 scratch2, | |
334 holder, | |
335 lookup, | |
336 name, | |
337 miss); | |
338 } else { | |
339 compiler->CompileRegular(masm, | |
340 receiver, | |
341 reg, | |
342 scratch2, | |
343 holder, | |
344 miss); | |
345 } | |
346 } | |
347 | |
348 | |
349 class LoadInterceptorCompiler BASE_EMBEDDED { | |
350 public: | |
351 explicit LoadInterceptorCompiler(Register name) : name_(name) {} | |
352 | |
353 void CompileCacheable(MacroAssembler* masm, | |
354 StubCompiler* stub_compiler, | |
355 Register receiver, | |
356 Register holder, | |
357 Register scratch1, | |
358 Register scratch2, | |
359 JSObject* interceptor_holder, | |
360 LookupResult* lookup, | |
361 String* name, | |
362 Label* miss_label) { | |
363 AccessorInfo* callback = NULL; | |
364 bool optimize = false; | |
365 // So far the most popular follow ups for interceptor loads are FIELD | |
366 // and CALLBACKS, so inline only them, other cases may be added | |
367 // later. | |
368 if (lookup->type() == FIELD) { | |
369 optimize = true; | |
370 } else if (lookup->type() == CALLBACKS) { | |
371 Object* callback_object = lookup->GetCallbackObject(); | |
372 if (callback_object->IsAccessorInfo()) { | |
373 callback = AccessorInfo::cast(callback_object); | |
374 optimize = callback->getter() != NULL; | |
375 } | |
376 } | |
377 | |
378 if (!optimize) { | |
379 CompileRegular(masm, receiver, holder, scratch2, interceptor_holder, | |
380 miss_label); | |
381 return; | |
382 } | |
383 | |
384 // Save necessary data before invoking an interceptor. | |
385 // Requires a frame to make GC aware of pushed pointers. | |
386 __ EnterInternalFrame(); | |
387 | |
388 if (lookup->type() == CALLBACKS && !receiver.is(holder)) { | |
389 // CALLBACKS case needs a receiver to be passed into C++ callback. | |
390 __ push(receiver); | |
391 } | |
392 __ push(holder); | |
393 __ push(name_); | |
394 | |
395 // Invoke an interceptor. Note: map checks from receiver to | |
396 // interceptor's holder has been compiled before (see a caller | |
397 // of this method.) | |
398 CompileCallLoadPropertyWithInterceptor(masm, | |
399 receiver, | |
400 holder, | |
401 name_, | |
402 interceptor_holder); | |
403 | |
404 // Check if interceptor provided a value for property. If it's | |
405 // the case, return immediately. | |
406 Label interceptor_failed; | |
407 __ cmp(eax, Factory::no_interceptor_result_sentinel()); | |
408 __ j(equal, &interceptor_failed); | |
409 __ LeaveInternalFrame(); | |
410 __ ret(0); | |
411 | |
412 __ bind(&interceptor_failed); | |
413 __ pop(name_); | |
414 __ pop(holder); | |
415 if (lookup->type() == CALLBACKS && !receiver.is(holder)) { | |
416 __ pop(receiver); | |
417 } | |
418 | |
419 __ LeaveInternalFrame(); | |
420 | |
421 // Check that the maps from interceptor's holder to lookup's holder | |
422 // haven't changed. And load lookup's holder into |holder| register. | |
423 if (interceptor_holder != lookup->holder()) { | |
424 holder = stub_compiler->CheckPrototypes(interceptor_holder, holder, | |
425 lookup->holder(), scratch1, | |
426 scratch2, | |
427 name, | |
428 miss_label); | |
429 } | |
430 | |
431 if (lookup->type() == FIELD) { | |
432 // We found FIELD property in prototype chain of interceptor's holder. | |
433 // Retrieve a field from field's holder. | |
434 stub_compiler->GenerateFastPropertyLoad(masm, eax, | |
435 holder, lookup->holder(), | |
436 lookup->GetFieldIndex()); | |
437 __ ret(0); | |
438 } else { | |
439 // We found CALLBACKS property in prototype chain of interceptor's | |
440 // holder. | |
441 ASSERT(lookup->type() == CALLBACKS); | |
442 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); | |
443 ASSERT(callback != NULL); | |
444 ASSERT(callback->getter() != NULL); | |
445 | |
446 // Tail call to runtime. | |
447 // Important invariant in CALLBACKS case: the code above must be | |
448 // structured to never clobber |receiver| register. | |
449 __ pop(scratch2); // return address | |
450 __ push(receiver); | |
451 __ push(holder); | |
452 __ mov(holder, Immediate(Handle<AccessorInfo>(callback))); | |
453 __ push(holder); | |
454 __ push(FieldOperand(holder, AccessorInfo::kDataOffset)); | |
455 __ push(name_); | |
456 __ push(scratch2); // restore return address | |
457 | |
458 ExternalReference ref = | |
459 ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); | |
460 __ TailCallExternalReference(ref, 5, 1); | |
461 } | |
462 } | |
463 | |
464 | |
465 void CompileRegular(MacroAssembler* masm, | |
466 Register receiver, | |
467 Register holder, | |
468 Register scratch, | |
469 JSObject* interceptor_holder, | |
470 Label* miss_label) { | |
471 __ pop(scratch); // save old return address | |
472 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder); | |
473 __ push(scratch); // restore old return address | |
474 | |
475 ExternalReference ref = ExternalReference( | |
476 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); | |
477 __ TailCallExternalReference(ref, 5, 1); | |
478 } | |
479 | |
480 private: | |
481 Register name_; | |
482 }; | |
483 | |
484 | |
485 // Reserves space for the extra arguments to FastHandleApiCall in the | 303 // Reserves space for the extra arguments to FastHandleApiCall in the |
486 // caller's frame. | 304 // caller's frame. |
487 // | 305 // |
488 // These arguments are set by CheckPrototypes and GenerateFastApiCall. | 306 // These arguments are set by CheckPrototypes and GenerateFastApiCall. |
489 static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { | 307 static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { |
490 // ----------- S t a t e ------------- | 308 // ----------- S t a t e ------------- |
491 // -- esp[0] : return address | 309 // -- esp[0] : return address |
492 // -- esp[4] : last argument in the internal frame of the caller | 310 // -- esp[4] : last argument in the internal frame of the caller |
493 // ----------------------------------- | 311 // ----------------------------------- |
494 __ pop(scratch); | 312 __ pop(scratch); |
(...skipping 549 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1044 CheckPrototypes(object, receiver, holder, | 862 CheckPrototypes(object, receiver, holder, |
1045 scratch1, scratch2, name, miss); | 863 scratch1, scratch2, name, miss); |
1046 | 864 |
1047 // Return the constant value. | 865 // Return the constant value. |
1048 __ mov(eax, Handle<Object>(value)); | 866 __ mov(eax, Handle<Object>(value)); |
1049 __ ret(0); | 867 __ ret(0); |
1050 } | 868 } |
1051 | 869 |
1052 | 870 |
1053 void StubCompiler::GenerateLoadInterceptor(JSObject* object, | 871 void StubCompiler::GenerateLoadInterceptor(JSObject* object, |
1054 JSObject* holder, | 872 JSObject* interceptor_holder, |
1055 LookupResult* lookup, | 873 LookupResult* lookup, |
1056 Register receiver, | 874 Register receiver, |
1057 Register name_reg, | 875 Register name_reg, |
1058 Register scratch1, | 876 Register scratch1, |
1059 Register scratch2, | 877 Register scratch2, |
1060 String* name, | 878 String* name, |
1061 Label* miss) { | 879 Label* miss) { |
1062 LoadInterceptorCompiler compiler(name_reg); | 880 ASSERT(interceptor_holder->HasNamedInterceptor()); |
1063 CompileLoadInterceptor(&compiler, | 881 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); |
1064 this, | 882 |
1065 masm(), | 883 // Check that the receiver isn't a smi. |
1066 object, | 884 __ test(receiver, Immediate(kSmiTagMask)); |
1067 holder, | 885 __ j(zero, miss, not_taken); |
1068 name, | 886 |
1069 lookup, | 887 // So far the most popular follow ups for interceptor loads are FIELD |
1070 receiver, | 888 // and CALLBACKS, so inline only them, other cases may be added |
1071 scratch1, | 889 // later. |
1072 scratch2, | 890 bool compile_followup_inline = false; |
1073 miss); | 891 if (lookup->IsProperty() && lookup->IsCacheable()) { |
892 if (lookup->type() == FIELD) { | |
893 compile_followup_inline = true; | |
894 } else if (lookup->type() == CALLBACKS && | |
895 lookup->GetCallbackObject()->IsAccessorInfo() && | |
896 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) { | |
897 compile_followup_inline = true; | |
898 } | |
899 } | |
900 | |
901 if (compile_followup_inline) { | |
902 // Compile the interceptor call, followed by inline code to load the | |
903 // property from further up the prototype chain if the call fails. | |
904 // Check that the maps haven't changed. | |
905 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, | |
906 scratch1, scratch2, name, miss); | |
907 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); | |
908 | |
909 // Save necessary data before invoking an interceptor. | |
910 // Requires a frame to make GC aware of pushed pointers. | |
911 __ EnterInternalFrame(); | |
912 | |
913 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { | |
914 // CALLBACKS case needs a receiver to be passed into C++ callback. | |
915 __ push(receiver); | |
916 } | |
917 __ push(holder_reg); | |
918 __ push(name_reg); | |
919 | |
920 // Invoke an interceptor. Note: map checks from receiver to | |
921 // interceptor's holder has been compiled before (see a caller | |
922 // of this method.) | |
923 CompileCallLoadPropertyWithInterceptor(masm(), | |
924 receiver, | |
925 holder_reg, | |
926 name_reg, | |
927 interceptor_holder); | |
928 | |
929 // Check if interceptor provided a value for property. If it's | |
930 // the case, return immediately. | |
931 Label interceptor_failed; | |
932 __ cmp(eax, Factory::no_interceptor_result_sentinel()); | |
933 __ j(equal, &interceptor_failed); | |
934 __ LeaveInternalFrame(); | |
935 __ ret(0); | |
936 | |
937 __ bind(&interceptor_failed); | |
938 __ pop(name_reg); | |
939 __ pop(holder_reg); | |
940 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { | |
941 __ pop(receiver); | |
942 } | |
943 | |
944 __ LeaveInternalFrame(); | |
945 | |
946 // Check that the maps from interceptor's holder to lookup's holder | |
947 // haven't changed. And load lookup's holder into holder_reg. | |
948 if (interceptor_holder != lookup->holder()) { | |
949 holder_reg = CheckPrototypes(interceptor_holder, | |
950 holder_reg, | |
951 lookup->holder(), | |
952 scratch1, | |
953 scratch2, | |
954 name, | |
955 miss); | |
956 } | |
antonm
2010/05/27 13:39:40
ditto for ia32 and x64
| |
957 | |
958 if (lookup->type() == FIELD) { | |
959 // We found FIELD property in prototype chain of interceptor's holder. | |
960 // Retrieve a field from field's holder. | |
961 GenerateFastPropertyLoad(masm(), eax, holder_reg, | |
962 lookup->holder(), lookup->GetFieldIndex()); | |
963 __ ret(0); | |
964 } else { | |
965 // We found CALLBACKS property in prototype chain of interceptor's | |
966 // holder. | |
967 ASSERT(lookup->type() == CALLBACKS); | |
968 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); | |
969 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); | |
970 ASSERT(callback != NULL); | |
971 ASSERT(callback->getter() != NULL); | |
972 | |
973 // Tail call to runtime. | |
974 // Important invariant in CALLBACKS case: the code above must be | |
975 // structured to never clobber |receiver| register. | |
976 __ pop(scratch2); // return address | |
977 __ push(receiver); | |
978 __ push(holder_reg); | |
979 __ mov(holder_reg, Immediate(Handle<AccessorInfo>(callback))); | |
980 __ push(holder_reg); | |
981 __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset)); | |
982 __ push(name_reg); | |
983 __ push(scratch2); // restore return address | |
984 | |
985 ExternalReference ref = | |
986 ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); | |
987 __ TailCallExternalReference(ref, 5, 1); | |
988 } | |
989 } else { // !compile_followup_inline | |
990 // Call the runtime system to load the interceptor. | |
991 // Check that the maps haven't changed. | |
992 Register holder_reg = | |
993 CheckPrototypes(object, receiver, interceptor_holder, | |
994 scratch1, scratch2, name, miss); | |
995 __ pop(scratch2); // save old return address | |
996 PushInterceptorArguments(masm(), receiver, holder_reg, | |
997 name_reg, interceptor_holder); | |
998 __ push(scratch2); // restore old return address | |
999 | |
1000 ExternalReference ref = ExternalReference( | |
1001 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); | |
1002 __ TailCallExternalReference(ref, 5, 1); | |
1003 } | |
1074 } | 1004 } |
1075 | 1005 |
1076 | 1006 |
1077 // TODO(1241006): Avoid having lazy compile stubs specialized by the | 1007 // TODO(1241006): Avoid having lazy compile stubs specialized by the |
1078 // number of arguments. It is not needed anymore. | 1008 // number of arguments. It is not needed anymore. |
1079 Object* StubCompiler::CompileLazyCompile(Code::Flags flags) { | 1009 Object* StubCompiler::CompileLazyCompile(Code::Flags flags) { |
1080 // Enter an internal frame. | 1010 // Enter an internal frame. |
1081 __ EnterInternalFrame(); | 1011 __ EnterInternalFrame(); |
1082 | 1012 |
1083 // Push a copy of the function onto the stack. | 1013 // Push a copy of the function onto the stack. |
(...skipping 1458 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2542 // Return the generated code. | 2472 // Return the generated code. |
2543 return GetCode(); | 2473 return GetCode(); |
2544 } | 2474 } |
2545 | 2475 |
2546 | 2476 |
2547 #undef __ | 2477 #undef __ |
2548 | 2478 |
2549 } } // namespace v8::internal | 2479 } } // namespace v8::internal |
2550 | 2480 |
2551 #endif // V8_TARGET_ARCH_IA32 | 2481 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |