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 2311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2322 StrictModeFlag strict_mode = ic.strict_mode(); | 2322 StrictModeFlag strict_mode = ic.strict_mode(); |
2323 return Runtime::SetObjectProperty(isolate, | 2323 return Runtime::SetObjectProperty(isolate, |
2324 object, | 2324 object, |
2325 key, | 2325 key, |
2326 value, | 2326 value, |
2327 NONE, | 2327 NONE, |
2328 strict_mode); | 2328 strict_mode); |
2329 } | 2329 } |
2330 | 2330 |
2331 | 2331 |
2332 void BinaryOpIC::patch(Code* code) { | |
2333 set_target(code); | |
2334 } | |
2335 | |
2336 | |
2337 const char* BinaryOpIC::GetName(TypeInfo type_info) { | 2332 const char* BinaryOpIC::GetName(TypeInfo type_info) { |
2338 switch (type_info) { | 2333 switch (type_info) { |
2339 case UNINITIALIZED: return "Uninitialized"; | 2334 case UNINITIALIZED: return "Uninitialized"; |
2340 case SMI: return "Smi"; | 2335 case SMI: return "Smi"; |
2341 case INT32: return "Int32"; | 2336 case INT32: return "Int32"; |
2342 case NUMBER: return "Number"; | 2337 case NUMBER: return "Number"; |
2343 case ODDBALL: return "Oddball"; | 2338 case ODDBALL: return "Oddball"; |
2344 case STRING: return "String"; | 2339 case STRING: return "String"; |
2345 case GENERIC: return "Generic"; | 2340 case GENERIC: return "Generic"; |
2346 default: return "Invalid"; | 2341 default: return "Invalid"; |
2347 } | 2342 } |
2348 } | 2343 } |
2349 | 2344 |
2350 | 2345 |
2351 BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { | 2346 MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) { |
2352 switch (type_info) { | 2347 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state(); |
2353 case UNINITIALIZED: | 2348 BinaryOpStub stub(extra_ic_state); |
2354 return ::v8::internal::UNINITIALIZED; | 2349 |
2355 case SMI: | 2350 bool smi_was_enabled = stub.GetLeftType(isolate())->Maybe(Type::Smi()) && |
2356 case INT32: | 2351 stub.GetRightType(isolate())->Maybe(Type::Smi()); |
2357 case NUMBER: | 2352 |
2358 case ODDBALL: | 2353 Maybe<Handle<Object> > result = stub.Result(left, right, isolate()); |
2359 case STRING: | 2354 |
2360 return MONOMORPHIC; | 2355 #ifdef DEBUG |
2361 case GENERIC: | 2356 if (FLAG_trace_ic) { |
2362 return ::v8::internal::GENERIC; | 2357 char buffer[100]; |
| 2358 NoAllocationStringAllocator allocator(buffer, |
| 2359 static_cast<unsigned>(sizeof(buffer))); |
| 2360 StringStream stream(&allocator); |
| 2361 stream.Add("["); |
| 2362 stub.PrintName(&stream); |
| 2363 |
| 2364 stub.UpdateStatus(left, right, result); |
| 2365 |
| 2366 stream.Add(" => "); |
| 2367 stub.PrintState(&stream); |
| 2368 stream.Add(" "); |
| 2369 stream.OutputToStdOut(); |
| 2370 PrintF(" @ %p <- ", static_cast<void*>(*stub.GetCode(isolate()))); |
| 2371 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); |
| 2372 PrintF("]\n"); |
| 2373 } else { |
| 2374 stub.UpdateStatus(left, right, result); |
2363 } | 2375 } |
2364 UNREACHABLE(); | 2376 #else |
2365 return ::v8::internal::UNINITIALIZED; | 2377 stub.UpdateStatus(left, right, result); |
| 2378 #endif |
| 2379 |
| 2380 Handle<Code> code = stub.GetCode(isolate()); |
| 2381 set_target(*code); |
| 2382 |
| 2383 bool enable_smi = stub.GetLeftType(isolate())->Maybe(Type::Smi()) && |
| 2384 stub.GetRightType(isolate())->Maybe(Type::Smi()); |
| 2385 |
| 2386 if (!smi_was_enabled && enable_smi) { |
| 2387 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); |
| 2388 } else if (smi_was_enabled && !enable_smi) { |
| 2389 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK); |
| 2390 } |
| 2391 |
| 2392 return result.has_value |
| 2393 ? static_cast<MaybeObject*>(*result.value) |
| 2394 : Failure::Exception(); |
2366 } | 2395 } |
2367 | 2396 |
2368 | 2397 |
2369 Handle<Type> BinaryOpIC::TypeInfoToType(BinaryOpIC::TypeInfo binary_type, | 2398 RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) { |
2370 Isolate* isolate) { | 2399 HandleScope scope(isolate); |
2371 switch (binary_type) { | 2400 Handle<Object> left = args.at<Object>(0); |
2372 case UNINITIALIZED: | 2401 Handle<Object> right = args.at<Object>(1); |
2373 return handle(Type::None(), isolate); | 2402 BinaryOpIC ic(isolate); |
2374 case SMI: | 2403 return ic.Transition(left, right); |
2375 return handle(Type::Smi(), isolate); | |
2376 case INT32: | |
2377 return handle(Type::Signed32(), isolate); | |
2378 case NUMBER: | |
2379 return handle(Type::Number(), isolate); | |
2380 case ODDBALL: | |
2381 return handle(Type::Optional( | |
2382 handle(Type::Union( | |
2383 handle(Type::Number(), isolate), | |
2384 handle(Type::String(), isolate)), isolate)), isolate); | |
2385 case STRING: | |
2386 return handle(Type::String(), isolate); | |
2387 case GENERIC: | |
2388 return handle(Type::Any(), isolate); | |
2389 } | |
2390 UNREACHABLE(); | |
2391 return handle(Type::Any(), isolate); | |
2392 } | 2404 } |
2393 | 2405 |
2394 | 2406 |
2395 void BinaryOpIC::StubInfoToType(int minor_key, | |
2396 Handle<Type>* left, | |
2397 Handle<Type>* right, | |
2398 Handle<Type>* result, | |
2399 Isolate* isolate) { | |
2400 TypeInfo left_typeinfo, right_typeinfo, result_typeinfo; | |
2401 BinaryOpStub::decode_types_from_minor_key( | |
2402 minor_key, &left_typeinfo, &right_typeinfo, &result_typeinfo); | |
2403 *left = TypeInfoToType(left_typeinfo, isolate); | |
2404 *right = TypeInfoToType(right_typeinfo, isolate); | |
2405 *result = TypeInfoToType(result_typeinfo, isolate); | |
2406 } | |
2407 | |
2408 | |
2409 static BinaryOpIC::TypeInfo TypeInfoFromValue(Handle<Object> value, | |
2410 Token::Value op) { | |
2411 v8::internal::TypeInfo type = v8::internal::TypeInfo::FromValue(value); | |
2412 if (type.IsSmi()) return BinaryOpIC::SMI; | |
2413 if (type.IsInteger32()) { | |
2414 if (SmiValuesAre32Bits()) return BinaryOpIC::SMI; | |
2415 return BinaryOpIC::INT32; | |
2416 } | |
2417 if (type.IsNumber()) return BinaryOpIC::NUMBER; | |
2418 if (type.IsString()) return BinaryOpIC::STRING; | |
2419 if (value->IsUndefined()) { | |
2420 if (op == Token::BIT_AND || | |
2421 op == Token::BIT_OR || | |
2422 op == Token::BIT_XOR || | |
2423 op == Token::SAR || | |
2424 op == Token::SHL || | |
2425 op == Token::SHR) { | |
2426 if (SmiValuesAre32Bits()) return BinaryOpIC::SMI; | |
2427 return BinaryOpIC::INT32; | |
2428 } | |
2429 return BinaryOpIC::ODDBALL; | |
2430 } | |
2431 return BinaryOpIC::GENERIC; | |
2432 } | |
2433 | |
2434 | |
2435 static BinaryOpIC::TypeInfo InputState(BinaryOpIC::TypeInfo old_type, | |
2436 Handle<Object> value, | |
2437 Token::Value op) { | |
2438 BinaryOpIC::TypeInfo new_type = TypeInfoFromValue(value, op); | |
2439 if (old_type == BinaryOpIC::STRING) { | |
2440 if (new_type == BinaryOpIC::STRING) return new_type; | |
2441 return BinaryOpIC::GENERIC; | |
2442 } | |
2443 return Max(old_type, new_type); | |
2444 } | |
2445 | |
2446 | |
2447 #ifdef DEBUG | |
2448 static void TraceBinaryOp(BinaryOpIC::TypeInfo left, | |
2449 BinaryOpIC::TypeInfo right, | |
2450 Maybe<int32_t> fixed_right_arg, | |
2451 BinaryOpIC::TypeInfo result) { | |
2452 PrintF("%s*%s", BinaryOpIC::GetName(left), BinaryOpIC::GetName(right)); | |
2453 if (fixed_right_arg.has_value) PrintF("{%d}", fixed_right_arg.value); | |
2454 PrintF("->%s", BinaryOpIC::GetName(result)); | |
2455 } | |
2456 #endif | |
2457 | |
2458 | |
2459 RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { | |
2460 ASSERT(args.length() == 3); | |
2461 | |
2462 HandleScope scope(isolate); | |
2463 Handle<Object> left = args.at<Object>(0); | |
2464 Handle<Object> right = args.at<Object>(1); | |
2465 int key = args.smi_at(2); | |
2466 Token::Value op = BinaryOpStub::decode_op_from_minor_key(key); | |
2467 | |
2468 BinaryOpIC::TypeInfo previous_left, previous_right, previous_result; | |
2469 BinaryOpStub::decode_types_from_minor_key( | |
2470 key, &previous_left, &previous_right, &previous_result); | |
2471 | |
2472 BinaryOpIC::TypeInfo new_left = InputState(previous_left, left, op); | |
2473 BinaryOpIC::TypeInfo new_right = InputState(previous_right, right, op); | |
2474 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED; | |
2475 | |
2476 // STRING is only used for ADD operations. | |
2477 if ((new_left == BinaryOpIC::STRING || new_right == BinaryOpIC::STRING) && | |
2478 op != Token::ADD) { | |
2479 new_left = new_right = BinaryOpIC::GENERIC; | |
2480 } | |
2481 | |
2482 BinaryOpIC::TypeInfo new_overall = Max(new_left, new_right); | |
2483 BinaryOpIC::TypeInfo previous_overall = Max(previous_left, previous_right); | |
2484 | |
2485 Maybe<int> previous_fixed_right_arg = | |
2486 BinaryOpStub::decode_fixed_right_arg_from_minor_key(key); | |
2487 | |
2488 int32_t value; | |
2489 bool new_has_fixed_right_arg = | |
2490 op == Token::MOD && | |
2491 right->ToInt32(&value) && | |
2492 BinaryOpStub::can_encode_arg_value(value) && | |
2493 (previous_overall == BinaryOpIC::UNINITIALIZED || | |
2494 (previous_fixed_right_arg.has_value && | |
2495 previous_fixed_right_arg.value == value)); | |
2496 Maybe<int32_t> new_fixed_right_arg( | |
2497 new_has_fixed_right_arg, new_has_fixed_right_arg ? value : 1); | |
2498 | |
2499 if (previous_fixed_right_arg.has_value == new_fixed_right_arg.has_value) { | |
2500 if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) { | |
2501 if (op == Token::DIV || | |
2502 op == Token::MUL || | |
2503 op == Token::SHR || | |
2504 SmiValuesAre32Bits()) { | |
2505 // Arithmetic on two Smi inputs has yielded a heap number. | |
2506 // That is the only way to get here from the Smi stub. | |
2507 // With 32-bit Smis, all overflows give heap numbers, but with | |
2508 // 31-bit Smis, most operations overflow to int32 results. | |
2509 result_type = BinaryOpIC::NUMBER; | |
2510 } else { | |
2511 // Other operations on SMIs that overflow yield int32s. | |
2512 result_type = BinaryOpIC::INT32; | |
2513 } | |
2514 } | |
2515 if (new_overall == BinaryOpIC::INT32 && | |
2516 previous_overall == BinaryOpIC::INT32) { | |
2517 if (new_left == previous_left && new_right == previous_right) { | |
2518 result_type = BinaryOpIC::NUMBER; | |
2519 } | |
2520 } | |
2521 } | |
2522 | |
2523 BinaryOpStub stub(key, new_left, new_right, result_type, new_fixed_right_arg); | |
2524 Handle<Code> code = stub.GetCode(isolate); | |
2525 if (!code.is_null()) { | |
2526 #ifdef DEBUG | |
2527 if (FLAG_trace_ic) { | |
2528 PrintF("[BinaryOpIC in "); | |
2529 JavaScriptFrame::PrintTop(isolate, stdout, false, true); | |
2530 PrintF(" "); | |
2531 TraceBinaryOp(previous_left, previous_right, previous_fixed_right_arg, | |
2532 previous_result); | |
2533 PrintF(" => "); | |
2534 TraceBinaryOp(new_left, new_right, new_fixed_right_arg, result_type); | |
2535 PrintF(" #%s @ %p]\n", Token::Name(op), static_cast<void*>(*code)); | |
2536 } | |
2537 #endif | |
2538 BinaryOpIC ic(isolate); | |
2539 ic.patch(*code); | |
2540 | |
2541 // Activate inlined smi code. | |
2542 if (previous_overall == BinaryOpIC::UNINITIALIZED) { | |
2543 PatchInlinedSmiCode(ic.address(), ENABLE_INLINED_SMI_CHECK); | |
2544 } | |
2545 } | |
2546 | |
2547 Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object()); | |
2548 Object* builtin = NULL; // Initialization calms down the compiler. | |
2549 switch (op) { | |
2550 case Token::ADD: | |
2551 builtin = builtins->javascript_builtin(Builtins::ADD); | |
2552 break; | |
2553 case Token::SUB: | |
2554 builtin = builtins->javascript_builtin(Builtins::SUB); | |
2555 break; | |
2556 case Token::MUL: | |
2557 builtin = builtins->javascript_builtin(Builtins::MUL); | |
2558 break; | |
2559 case Token::DIV: | |
2560 builtin = builtins->javascript_builtin(Builtins::DIV); | |
2561 break; | |
2562 case Token::MOD: | |
2563 builtin = builtins->javascript_builtin(Builtins::MOD); | |
2564 break; | |
2565 case Token::BIT_AND: | |
2566 builtin = builtins->javascript_builtin(Builtins::BIT_AND); | |
2567 break; | |
2568 case Token::BIT_OR: | |
2569 builtin = builtins->javascript_builtin(Builtins::BIT_OR); | |
2570 break; | |
2571 case Token::BIT_XOR: | |
2572 builtin = builtins->javascript_builtin(Builtins::BIT_XOR); | |
2573 break; | |
2574 case Token::SHR: | |
2575 builtin = builtins->javascript_builtin(Builtins::SHR); | |
2576 break; | |
2577 case Token::SAR: | |
2578 builtin = builtins->javascript_builtin(Builtins::SAR); | |
2579 break; | |
2580 case Token::SHL: | |
2581 builtin = builtins->javascript_builtin(Builtins::SHL); | |
2582 break; | |
2583 default: | |
2584 UNREACHABLE(); | |
2585 } | |
2586 | |
2587 Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate); | |
2588 | |
2589 bool caught_exception; | |
2590 Handle<Object> builtin_args[] = { right }; | |
2591 Handle<Object> result = Execution::Call(isolate, | |
2592 builtin_function, | |
2593 left, | |
2594 ARRAY_SIZE(builtin_args), | |
2595 builtin_args, | |
2596 &caught_exception); | |
2597 if (caught_exception) { | |
2598 return Failure::Exception(); | |
2599 } | |
2600 return *result; | |
2601 } | |
2602 | |
2603 | |
2604 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { | 2407 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { |
2605 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2408 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
2606 Code* code = NULL; | 2409 Code* code = NULL; |
2607 CHECK(stub.FindCodeInCache(&code, isolate)); | 2410 CHECK(stub.FindCodeInCache(&code, isolate)); |
2608 return code; | 2411 return code; |
2609 } | 2412 } |
2610 | 2413 |
2611 | 2414 |
2612 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { | 2415 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { |
2613 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2416 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2891 } | 2694 } |
2892 | 2695 |
2893 | 2696 |
2894 RUNTIME_FUNCTION(MaybeObject*, Unreachable) { | 2697 RUNTIME_FUNCTION(MaybeObject*, Unreachable) { |
2895 UNREACHABLE(); | 2698 UNREACHABLE(); |
2896 CHECK(false); | 2699 CHECK(false); |
2897 return isolate->heap()->undefined_value(); | 2700 return isolate->heap()->undefined_value(); |
2898 } | 2701 } |
2899 | 2702 |
2900 | 2703 |
| 2704 Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op) { |
| 2705 switch (op) { |
| 2706 default: |
| 2707 UNREACHABLE(); |
| 2708 case Token::ADD: |
| 2709 return Builtins::ADD; |
| 2710 break; |
| 2711 case Token::SUB: |
| 2712 return Builtins::SUB; |
| 2713 break; |
| 2714 case Token::MUL: |
| 2715 return Builtins::MUL; |
| 2716 break; |
| 2717 case Token::DIV: |
| 2718 return Builtins::DIV; |
| 2719 break; |
| 2720 case Token::MOD: |
| 2721 return Builtins::MOD; |
| 2722 break; |
| 2723 case Token::BIT_OR: |
| 2724 return Builtins::BIT_OR; |
| 2725 break; |
| 2726 case Token::BIT_AND: |
| 2727 return Builtins::BIT_AND; |
| 2728 break; |
| 2729 case Token::BIT_XOR: |
| 2730 return Builtins::BIT_XOR; |
| 2731 break; |
| 2732 case Token::SAR: |
| 2733 return Builtins::SAR; |
| 2734 break; |
| 2735 case Token::SHR: |
| 2736 return Builtins::SHR; |
| 2737 break; |
| 2738 case Token::SHL: |
| 2739 return Builtins::SHL; |
| 2740 break; |
| 2741 } |
| 2742 } |
| 2743 |
| 2744 |
2901 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object, | 2745 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object, |
2902 Code::ExtraICState extra_ic_state) { | 2746 Code::ExtraICState extra_ic_state) { |
2903 ToBooleanStub stub(extra_ic_state); | 2747 ToBooleanStub stub(extra_ic_state); |
2904 bool to_boolean_value = stub.UpdateStatus(object); | 2748 bool to_boolean_value = stub.UpdateStatus(object); |
2905 Handle<Code> code = stub.GetCode(isolate()); | 2749 Handle<Code> code = stub.GetCode(isolate()); |
2906 set_target(*code); | 2750 set_target(*code); |
2907 return Smi::FromInt(to_boolean_value ? 1 : 0); | 2751 return Smi::FromInt(to_boolean_value ? 1 : 0); |
2908 } | 2752 } |
2909 | 2753 |
2910 | 2754 |
(...skipping 14 matching lines...) Expand all Loading... |
2925 #undef ADDR | 2769 #undef ADDR |
2926 }; | 2770 }; |
2927 | 2771 |
2928 | 2772 |
2929 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2773 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
2930 return IC_utilities[id]; | 2774 return IC_utilities[id]; |
2931 } | 2775 } |
2932 | 2776 |
2933 | 2777 |
2934 } } // namespace v8::internal | 2778 } } // namespace v8::internal |
OLD | NEW |