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 |
2374 const char* BinaryOpIC::GetName(TypeInfo type_info) { | 2379 const char* BinaryOpIC::GetName(TypeInfo type_info) { |
2375 switch (type_info) { | 2380 switch (type_info) { |
2376 case UNINITIALIZED: return "Uninitialized"; | 2381 case UNINITIALIZED: return "Uninitialized"; |
2377 case SMI: return "Smi"; | 2382 case SMI: return "Smi"; |
2378 case INT32: return "Int32"; | 2383 case INT32: return "Int32"; |
2379 case NUMBER: return "Number"; | 2384 case NUMBER: return "Number"; |
2380 case ODDBALL: return "Oddball"; | 2385 case ODDBALL: return "Oddball"; |
2381 case STRING: return "String"; | 2386 case STRING: return "String"; |
2382 case GENERIC: return "Generic"; | 2387 case GENERIC: return "Generic"; |
2383 default: return "Invalid"; | 2388 default: return "Invalid"; |
2384 } | 2389 } |
2385 } | 2390 } |
2386 | 2391 |
2387 | 2392 |
2388 MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) { | 2393 BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { |
2389 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state(); | 2394 switch (type_info) { |
2390 BinaryOpStub stub(extra_ic_state); | 2395 case UNINITIALIZED: |
2391 | 2396 return ::v8::internal::UNINITIALIZED; |
2392 bool smi_was_enabled = stub.GetLeftType(isolate())->Maybe(Type::Smi()) && | 2397 case SMI: |
2393 stub.GetRightType(isolate())->Maybe(Type::Smi()); | 2398 case INT32: |
2394 | 2399 case NUMBER: |
2395 Maybe<Handle<Object> > result = stub.Result(left, right, isolate()); | 2400 case ODDBALL: |
| 2401 case STRING: |
| 2402 return MONOMORPHIC; |
| 2403 case GENERIC: |
| 2404 return ::v8::internal::GENERIC; |
| 2405 } |
| 2406 UNREACHABLE(); |
| 2407 return ::v8::internal::UNINITIALIZED; |
| 2408 } |
| 2409 |
| 2410 |
| 2411 Handle<Type> BinaryOpIC::TypeInfoToType(BinaryOpIC::TypeInfo binary_type, |
| 2412 Isolate* isolate) { |
| 2413 switch (binary_type) { |
| 2414 case UNINITIALIZED: |
| 2415 return handle(Type::None(), isolate); |
| 2416 case SMI: |
| 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 } |
| 2435 |
| 2436 |
| 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 |
2396 | 2488 |
2397 #ifdef DEBUG | 2489 #ifdef DEBUG |
2398 if (FLAG_trace_ic) { | 2490 static void TraceBinaryOp(BinaryOpIC::TypeInfo left, |
2399 char buffer[100]; | 2491 BinaryOpIC::TypeInfo right, |
2400 NoAllocationStringAllocator allocator(buffer, | 2492 Maybe<int32_t> fixed_right_arg, |
2401 static_cast<unsigned>(sizeof(buffer))); | 2493 BinaryOpIC::TypeInfo result) { |
2402 StringStream stream(&allocator); | 2494 PrintF("%s*%s", BinaryOpIC::GetName(left), BinaryOpIC::GetName(right)); |
2403 stream.Add("["); | 2495 if (fixed_right_arg.has_value) PrintF("{%d}", fixed_right_arg.value); |
2404 stub.PrintName(&stream); | 2496 PrintF("->%s", BinaryOpIC::GetName(result)); |
2405 | 2497 } |
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); | |
2417 } | |
2418 #else | |
2419 stub.UpdateStatus(left, right, result); | |
2420 #endif | 2498 #endif |
2421 | 2499 |
2422 Handle<Code> code = stub.GetCode(isolate()); | 2500 |
2423 set_target(*code); | 2501 RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { |
2424 | 2502 ASSERT(args.length() == 3); |
2425 bool enable_smi = stub.GetLeftType(isolate())->Maybe(Type::Smi()) && | 2503 |
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(); | |
2437 } | |
2438 | |
2439 | |
2440 RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) { | |
2441 HandleScope scope(isolate); | 2504 HandleScope scope(isolate); |
2442 Handle<Object> left = args.at<Object>(0); | 2505 Handle<Object> left = args.at<Object>(0); |
2443 Handle<Object> right = args.at<Object>(1); | 2506 Handle<Object> right = args.at<Object>(1); |
2444 BinaryOpIC ic(isolate); | 2507 int key = args.smi_at(2); |
2445 return ic.Transition(left, right); | 2508 Token::Value op = BinaryOpStub::decode_op_from_minor_key(key); |
2446 } | 2509 |
2447 | 2510 BinaryOpIC::TypeInfo previous_left, previous_right, previous_result; |
2448 | 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 |
2449 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { | 2646 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { |
2450 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2647 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
2451 Code* code = NULL; | 2648 Code* code = NULL; |
2452 CHECK(stub.FindCodeInCache(&code, isolate)); | 2649 CHECK(stub.FindCodeInCache(&code, isolate)); |
2453 return code; | 2650 return code; |
2454 } | 2651 } |
2455 | 2652 |
2456 | 2653 |
2457 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { | 2654 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { |
2458 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2655 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2736 } | 2933 } |
2737 | 2934 |
2738 | 2935 |
2739 RUNTIME_FUNCTION(MaybeObject*, Unreachable) { | 2936 RUNTIME_FUNCTION(MaybeObject*, Unreachable) { |
2740 UNREACHABLE(); | 2937 UNREACHABLE(); |
2741 CHECK(false); | 2938 CHECK(false); |
2742 return isolate->heap()->undefined_value(); | 2939 return isolate->heap()->undefined_value(); |
2743 } | 2940 } |
2744 | 2941 |
2745 | 2942 |
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 | |
2787 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object, | 2943 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object, |
2788 Code::ExtraICState extra_ic_state) { | 2944 Code::ExtraICState extra_ic_state) { |
2789 ToBooleanStub stub(extra_ic_state); | 2945 ToBooleanStub stub(extra_ic_state); |
2790 bool to_boolean_value = stub.UpdateStatus(object); | 2946 bool to_boolean_value = stub.UpdateStatus(object); |
2791 Handle<Code> code = stub.GetCode(isolate()); | 2947 Handle<Code> code = stub.GetCode(isolate()); |
2792 set_target(*code); | 2948 set_target(*code); |
2793 return Smi::FromInt(to_boolean_value ? 1 : 0); | 2949 return Smi::FromInt(to_boolean_value ? 1 : 0); |
2794 } | 2950 } |
2795 | 2951 |
2796 | 2952 |
(...skipping 14 matching lines...) Expand all Loading... |
2811 #undef ADDR | 2967 #undef ADDR |
2812 }; | 2968 }; |
2813 | 2969 |
2814 | 2970 |
2815 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2971 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
2816 return IC_utilities[id]; | 2972 return IC_utilities[id]; |
2817 } | 2973 } |
2818 | 2974 |
2819 | 2975 |
2820 } } // namespace v8::internal | 2976 } } // namespace v8::internal |
OLD | NEW |