OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 2353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2364 StrictModeFlag strict_mode = ic.strict_mode(); | 2364 StrictModeFlag strict_mode = ic.strict_mode(); |
2365 return Runtime::SetObjectProperty(isolate, | 2365 return Runtime::SetObjectProperty(isolate, |
2366 object, | 2366 object, |
2367 key, | 2367 key, |
2368 value, | 2368 value, |
2369 NONE, | 2369 NONE, |
2370 strict_mode); | 2370 strict_mode); |
2371 } | 2371 } |
2372 | 2372 |
2373 | 2373 |
2374 void BinaryOpIC::patch(Code* code) { | |
2375 set_target(code); | |
2376 } | |
2377 | |
2378 | |
2379 const char* BinaryOpIC::GetName(TypeInfo type_info) { | 2374 const char* BinaryOpIC::GetName(TypeInfo type_info) { |
2380 switch (type_info) { | 2375 switch (type_info) { |
2381 case UNINITIALIZED: return "Uninitialized"; | 2376 case UNINITIALIZED: return "Uninitialized"; |
2382 case SMI: return "Smi"; | 2377 case SMI: return "Smi"; |
2383 case INT32: return "Int32"; | 2378 case INT32: return "Int32"; |
2384 case NUMBER: return "Number"; | 2379 case NUMBER: return "Number"; |
2385 case ODDBALL: return "Oddball"; | 2380 case ODDBALL: return "Oddball"; |
2386 case STRING: return "String"; | 2381 case STRING: return "String"; |
2387 case GENERIC: return "Generic"; | 2382 case GENERIC: return "Generic"; |
2388 default: return "Invalid"; | 2383 default: return "Invalid"; |
2389 } | 2384 } |
2390 } | 2385 } |
2391 | 2386 |
2392 | 2387 |
2393 BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { | 2388 MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) { |
2394 switch (type_info) { | 2389 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state(); |
2395 case UNINITIALIZED: | 2390 BinaryOpStub stub(extra_ic_state); |
2396 return ::v8::internal::UNINITIALIZED; | 2391 |
2397 case SMI: | 2392 bool smi_was_enabled = stub.GetLeftType(isolate())->Maybe(Type::Smi()) && |
2398 case INT32: | 2393 stub.GetRightType(isolate())->Maybe(Type::Smi()); |
2399 case NUMBER: | 2394 |
2400 case ODDBALL: | 2395 Maybe<Handle<Object> > result = stub.Result(left, right, isolate()); |
2401 case STRING: | 2396 |
2402 return MONOMORPHIC; | 2397 #ifdef DEBUG |
2403 case GENERIC: | 2398 if (FLAG_trace_ic) { |
2404 return ::v8::internal::GENERIC; | 2399 char buffer[100]; |
| 2400 NoAllocationStringAllocator allocator(buffer, |
| 2401 static_cast<unsigned>(sizeof(buffer))); |
| 2402 StringStream stream(&allocator); |
| 2403 stream.Add("["); |
| 2404 stub.PrintName(&stream); |
| 2405 |
| 2406 stub.UpdateStatus(left, right, result); |
| 2407 |
| 2408 stream.Add(" => "); |
| 2409 stub.PrintState(&stream); |
| 2410 stream.Add(" "); |
| 2411 stream.OutputToStdOut(); |
| 2412 PrintF(" @ %p <- ", static_cast<void*>(*stub.GetCode(isolate()))); |
| 2413 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); |
| 2414 PrintF("]\n"); |
| 2415 } else { |
| 2416 stub.UpdateStatus(left, right, result); |
2405 } | 2417 } |
2406 UNREACHABLE(); | 2418 #else |
2407 return ::v8::internal::UNINITIALIZED; | 2419 stub.UpdateStatus(left, right, result); |
| 2420 #endif |
| 2421 |
| 2422 Handle<Code> code = stub.GetCode(isolate()); |
| 2423 set_target(*code); |
| 2424 |
| 2425 bool enable_smi = stub.GetLeftType(isolate())->Maybe(Type::Smi()) && |
| 2426 stub.GetRightType(isolate())->Maybe(Type::Smi()); |
| 2427 |
| 2428 if (!smi_was_enabled && enable_smi) { |
| 2429 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); |
| 2430 } else if (smi_was_enabled && !enable_smi) { |
| 2431 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK); |
| 2432 } |
| 2433 |
| 2434 return result.has_value |
| 2435 ? static_cast<MaybeObject*>(*result.value) |
| 2436 : Failure::Exception(); |
2408 } | 2437 } |
2409 | 2438 |
2410 | 2439 |
2411 Handle<Type> BinaryOpIC::TypeInfoToType(BinaryOpIC::TypeInfo binary_type, | 2440 RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) { |
2412 Isolate* isolate) { | 2441 HandleScope scope(isolate); |
2413 switch (binary_type) { | 2442 Handle<Object> left = args.at<Object>(0); |
2414 case UNINITIALIZED: | 2443 Handle<Object> right = args.at<Object>(1); |
2415 return handle(Type::None(), isolate); | 2444 BinaryOpIC ic(isolate); |
2416 case SMI: | 2445 return ic.Transition(left, right); |
2417 return handle(Type::Smi(), isolate); | |
2418 case INT32: | |
2419 return handle(Type::Signed32(), isolate); | |
2420 case NUMBER: | |
2421 return handle(Type::Number(), isolate); | |
2422 case ODDBALL: | |
2423 return handle(Type::Optional( | |
2424 handle(Type::Union( | |
2425 handle(Type::Number(), isolate), | |
2426 handle(Type::String(), isolate)), isolate)), isolate); | |
2427 case STRING: | |
2428 return handle(Type::String(), isolate); | |
2429 case GENERIC: | |
2430 return handle(Type::Any(), isolate); | |
2431 } | |
2432 UNREACHABLE(); | |
2433 return handle(Type::Any(), isolate); | |
2434 } | 2446 } |
2435 | 2447 |
2436 | 2448 |
2437 void BinaryOpIC::StubInfoToType(int minor_key, | |
2438 Handle<Type>* left, | |
2439 Handle<Type>* right, | |
2440 Handle<Type>* result, | |
2441 Isolate* isolate) { | |
2442 TypeInfo left_typeinfo, right_typeinfo, result_typeinfo; | |
2443 BinaryOpStub::decode_types_from_minor_key( | |
2444 minor_key, &left_typeinfo, &right_typeinfo, &result_typeinfo); | |
2445 *left = TypeInfoToType(left_typeinfo, isolate); | |
2446 *right = TypeInfoToType(right_typeinfo, isolate); | |
2447 *result = TypeInfoToType(result_typeinfo, isolate); | |
2448 } | |
2449 | |
2450 | |
2451 static BinaryOpIC::TypeInfo TypeInfoFromValue(Handle<Object> value, | |
2452 Token::Value op) { | |
2453 v8::internal::TypeInfo type = v8::internal::TypeInfo::FromValue(value); | |
2454 if (type.IsSmi()) return BinaryOpIC::SMI; | |
2455 if (type.IsInteger32()) { | |
2456 if (SmiValuesAre32Bits()) return BinaryOpIC::SMI; | |
2457 return BinaryOpIC::INT32; | |
2458 } | |
2459 if (type.IsNumber()) return BinaryOpIC::NUMBER; | |
2460 if (type.IsString()) return BinaryOpIC::STRING; | |
2461 if (value->IsUndefined()) { | |
2462 if (op == Token::BIT_AND || | |
2463 op == Token::BIT_OR || | |
2464 op == Token::BIT_XOR || | |
2465 op == Token::SAR || | |
2466 op == Token::SHL || | |
2467 op == Token::SHR) { | |
2468 if (SmiValuesAre32Bits()) return BinaryOpIC::SMI; | |
2469 return BinaryOpIC::INT32; | |
2470 } | |
2471 return BinaryOpIC::ODDBALL; | |
2472 } | |
2473 return BinaryOpIC::GENERIC; | |
2474 } | |
2475 | |
2476 | |
2477 static BinaryOpIC::TypeInfo InputState(BinaryOpIC::TypeInfo old_type, | |
2478 Handle<Object> value, | |
2479 Token::Value op) { | |
2480 BinaryOpIC::TypeInfo new_type = TypeInfoFromValue(value, op); | |
2481 if (old_type == BinaryOpIC::STRING) { | |
2482 if (new_type == BinaryOpIC::STRING) return new_type; | |
2483 return BinaryOpIC::GENERIC; | |
2484 } | |
2485 return Max(old_type, new_type); | |
2486 } | |
2487 | |
2488 | |
2489 #ifdef DEBUG | |
2490 static void TraceBinaryOp(BinaryOpIC::TypeInfo left, | |
2491 BinaryOpIC::TypeInfo right, | |
2492 Maybe<int32_t> fixed_right_arg, | |
2493 BinaryOpIC::TypeInfo result) { | |
2494 PrintF("%s*%s", BinaryOpIC::GetName(left), BinaryOpIC::GetName(right)); | |
2495 if (fixed_right_arg.has_value) PrintF("{%d}", fixed_right_arg.value); | |
2496 PrintF("->%s", BinaryOpIC::GetName(result)); | |
2497 } | |
2498 #endif | |
2499 | |
2500 | |
2501 RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { | |
2502 ASSERT(args.length() == 3); | |
2503 | |
2504 HandleScope scope(isolate); | |
2505 Handle<Object> left = args.at<Object>(0); | |
2506 Handle<Object> right = args.at<Object>(1); | |
2507 int key = args.smi_at(2); | |
2508 Token::Value op = BinaryOpStub::decode_op_from_minor_key(key); | |
2509 | |
2510 BinaryOpIC::TypeInfo previous_left, previous_right, previous_result; | |
2511 BinaryOpStub::decode_types_from_minor_key( | |
2512 key, &previous_left, &previous_right, &previous_result); | |
2513 | |
2514 BinaryOpIC::TypeInfo new_left = InputState(previous_left, left, op); | |
2515 BinaryOpIC::TypeInfo new_right = InputState(previous_right, right, op); | |
2516 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED; | |
2517 | |
2518 // STRING is only used for ADD operations. | |
2519 if ((new_left == BinaryOpIC::STRING || new_right == BinaryOpIC::STRING) && | |
2520 op != Token::ADD) { | |
2521 new_left = new_right = BinaryOpIC::GENERIC; | |
2522 } | |
2523 | |
2524 BinaryOpIC::TypeInfo new_overall = Max(new_left, new_right); | |
2525 BinaryOpIC::TypeInfo previous_overall = Max(previous_left, previous_right); | |
2526 | |
2527 Maybe<int> previous_fixed_right_arg = | |
2528 BinaryOpStub::decode_fixed_right_arg_from_minor_key(key); | |
2529 | |
2530 int32_t value; | |
2531 bool new_has_fixed_right_arg = | |
2532 op == Token::MOD && | |
2533 right->ToInt32(&value) && | |
2534 BinaryOpStub::can_encode_arg_value(value) && | |
2535 (previous_overall == BinaryOpIC::UNINITIALIZED || | |
2536 (previous_fixed_right_arg.has_value && | |
2537 previous_fixed_right_arg.value == value)); | |
2538 Maybe<int32_t> new_fixed_right_arg( | |
2539 new_has_fixed_right_arg, new_has_fixed_right_arg ? value : 1); | |
2540 | |
2541 if (previous_fixed_right_arg.has_value == new_fixed_right_arg.has_value) { | |
2542 if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) { | |
2543 if (op == Token::DIV || | |
2544 op == Token::MUL || | |
2545 op == Token::SHR || | |
2546 SmiValuesAre32Bits()) { | |
2547 // Arithmetic on two Smi inputs has yielded a heap number. | |
2548 // That is the only way to get here from the Smi stub. | |
2549 // With 32-bit Smis, all overflows give heap numbers, but with | |
2550 // 31-bit Smis, most operations overflow to int32 results. | |
2551 result_type = BinaryOpIC::NUMBER; | |
2552 } else { | |
2553 // Other operations on SMIs that overflow yield int32s. | |
2554 result_type = BinaryOpIC::INT32; | |
2555 } | |
2556 } | |
2557 if (new_overall == BinaryOpIC::INT32 && | |
2558 previous_overall == BinaryOpIC::INT32) { | |
2559 if (new_left == previous_left && new_right == previous_right) { | |
2560 result_type = BinaryOpIC::NUMBER; | |
2561 } | |
2562 } | |
2563 } | |
2564 | |
2565 BinaryOpStub stub(key, new_left, new_right, result_type, new_fixed_right_arg); | |
2566 Handle<Code> code = stub.GetCode(isolate); | |
2567 if (!code.is_null()) { | |
2568 #ifdef DEBUG | |
2569 if (FLAG_trace_ic) { | |
2570 PrintF("[BinaryOpIC in "); | |
2571 JavaScriptFrame::PrintTop(isolate, stdout, false, true); | |
2572 PrintF(" "); | |
2573 TraceBinaryOp(previous_left, previous_right, previous_fixed_right_arg, | |
2574 previous_result); | |
2575 PrintF(" => "); | |
2576 TraceBinaryOp(new_left, new_right, new_fixed_right_arg, result_type); | |
2577 PrintF(" #%s @ %p]\n", Token::Name(op), static_cast<void*>(*code)); | |
2578 } | |
2579 #endif | |
2580 BinaryOpIC ic(isolate); | |
2581 ic.patch(*code); | |
2582 | |
2583 // Activate inlined smi code. | |
2584 if (previous_overall == BinaryOpIC::UNINITIALIZED) { | |
2585 PatchInlinedSmiCode(ic.address(), ENABLE_INLINED_SMI_CHECK); | |
2586 } | |
2587 } | |
2588 | |
2589 Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object()); | |
2590 Object* builtin = NULL; // Initialization calms down the compiler. | |
2591 switch (op) { | |
2592 case Token::ADD: | |
2593 builtin = builtins->javascript_builtin(Builtins::ADD); | |
2594 break; | |
2595 case Token::SUB: | |
2596 builtin = builtins->javascript_builtin(Builtins::SUB); | |
2597 break; | |
2598 case Token::MUL: | |
2599 builtin = builtins->javascript_builtin(Builtins::MUL); | |
2600 break; | |
2601 case Token::DIV: | |
2602 builtin = builtins->javascript_builtin(Builtins::DIV); | |
2603 break; | |
2604 case Token::MOD: | |
2605 builtin = builtins->javascript_builtin(Builtins::MOD); | |
2606 break; | |
2607 case Token::BIT_AND: | |
2608 builtin = builtins->javascript_builtin(Builtins::BIT_AND); | |
2609 break; | |
2610 case Token::BIT_OR: | |
2611 builtin = builtins->javascript_builtin(Builtins::BIT_OR); | |
2612 break; | |
2613 case Token::BIT_XOR: | |
2614 builtin = builtins->javascript_builtin(Builtins::BIT_XOR); | |
2615 break; | |
2616 case Token::SHR: | |
2617 builtin = builtins->javascript_builtin(Builtins::SHR); | |
2618 break; | |
2619 case Token::SAR: | |
2620 builtin = builtins->javascript_builtin(Builtins::SAR); | |
2621 break; | |
2622 case Token::SHL: | |
2623 builtin = builtins->javascript_builtin(Builtins::SHL); | |
2624 break; | |
2625 default: | |
2626 UNREACHABLE(); | |
2627 } | |
2628 | |
2629 Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate); | |
2630 | |
2631 bool caught_exception; | |
2632 Handle<Object> builtin_args[] = { right }; | |
2633 Handle<Object> result = Execution::Call(isolate, | |
2634 builtin_function, | |
2635 left, | |
2636 ARRAY_SIZE(builtin_args), | |
2637 builtin_args, | |
2638 &caught_exception); | |
2639 if (caught_exception) { | |
2640 return Failure::Exception(); | |
2641 } | |
2642 return *result; | |
2643 } | |
2644 | |
2645 | |
2646 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { | 2449 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { |
2647 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2450 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
2648 Code* code = NULL; | 2451 Code* code = NULL; |
2649 CHECK(stub.FindCodeInCache(&code, isolate)); | 2452 CHECK(stub.FindCodeInCache(&code, isolate)); |
2650 return code; | 2453 return code; |
2651 } | 2454 } |
2652 | 2455 |
2653 | 2456 |
2654 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { | 2457 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { |
2655 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2458 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2933 } | 2736 } |
2934 | 2737 |
2935 | 2738 |
2936 RUNTIME_FUNCTION(MaybeObject*, Unreachable) { | 2739 RUNTIME_FUNCTION(MaybeObject*, Unreachable) { |
2937 UNREACHABLE(); | 2740 UNREACHABLE(); |
2938 CHECK(false); | 2741 CHECK(false); |
2939 return isolate->heap()->undefined_value(); | 2742 return isolate->heap()->undefined_value(); |
2940 } | 2743 } |
2941 | 2744 |
2942 | 2745 |
| 2746 Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op) { |
| 2747 switch (op) { |
| 2748 default: |
| 2749 UNREACHABLE(); |
| 2750 case Token::ADD: |
| 2751 return Builtins::ADD; |
| 2752 break; |
| 2753 case Token::SUB: |
| 2754 return Builtins::SUB; |
| 2755 break; |
| 2756 case Token::MUL: |
| 2757 return Builtins::MUL; |
| 2758 break; |
| 2759 case Token::DIV: |
| 2760 return Builtins::DIV; |
| 2761 break; |
| 2762 case Token::MOD: |
| 2763 return Builtins::MOD; |
| 2764 break; |
| 2765 case Token::BIT_OR: |
| 2766 return Builtins::BIT_OR; |
| 2767 break; |
| 2768 case Token::BIT_AND: |
| 2769 return Builtins::BIT_AND; |
| 2770 break; |
| 2771 case Token::BIT_XOR: |
| 2772 return Builtins::BIT_XOR; |
| 2773 break; |
| 2774 case Token::SAR: |
| 2775 return Builtins::SAR; |
| 2776 break; |
| 2777 case Token::SHR: |
| 2778 return Builtins::SHR; |
| 2779 break; |
| 2780 case Token::SHL: |
| 2781 return Builtins::SHL; |
| 2782 break; |
| 2783 } |
| 2784 } |
| 2785 |
| 2786 |
2943 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object, | 2787 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object, |
2944 Code::ExtraICState extra_ic_state) { | 2788 Code::ExtraICState extra_ic_state) { |
2945 ToBooleanStub stub(extra_ic_state); | 2789 ToBooleanStub stub(extra_ic_state); |
2946 bool to_boolean_value = stub.UpdateStatus(object); | 2790 bool to_boolean_value = stub.UpdateStatus(object); |
2947 Handle<Code> code = stub.GetCode(isolate()); | 2791 Handle<Code> code = stub.GetCode(isolate()); |
2948 set_target(*code); | 2792 set_target(*code); |
2949 return Smi::FromInt(to_boolean_value ? 1 : 0); | 2793 return Smi::FromInt(to_boolean_value ? 1 : 0); |
2950 } | 2794 } |
2951 | 2795 |
2952 | 2796 |
(...skipping 14 matching lines...) Expand all Loading... |
2967 #undef ADDR | 2811 #undef ADDR |
2968 }; | 2812 }; |
2969 | 2813 |
2970 | 2814 |
2971 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2815 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
2972 return IC_utilities[id]; | 2816 return IC_utilities[id]; |
2973 } | 2817 } |
2974 | 2818 |
2975 | 2819 |
2976 } } // namespace v8::internal | 2820 } } // namespace v8::internal |
OLD | NEW |