OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 2297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2308 ContextualMode mode, | 2308 ContextualMode mode, |
2309 TypeFeedbackId ast_id) { | 2309 TypeFeedbackId ast_id) { |
2310 ic_total_count_++; | 2310 ic_total_count_++; |
2311 // All calls must have a predictable size in full-codegen code to ensure that | 2311 // All calls must have a predictable size in full-codegen code to ensure that |
2312 // the debugger can patch them correctly. | 2312 // the debugger can patch them correctly. |
2313 ASSERT((mode != CONTEXTUAL) || ast_id.IsNone()); | 2313 ASSERT((mode != CONTEXTUAL) || ast_id.IsNone()); |
2314 __ Call(code, RelocInfo::CODE_TARGET, ast_id); | 2314 __ Call(code, RelocInfo::CODE_TARGET, ast_id); |
2315 } | 2315 } |
2316 | 2316 |
2317 | 2317 |
2318 void FullCodeGenerator::EmitCallWithIC(Call* expr, | 2318 // Code common for calls using the IC. |
2319 Handle<Object> name, | 2319 void FullCodeGenerator::EmitCallWithIC(Call* expr) { |
2320 ContextualMode mode) { | |
2321 ASM_LOCATION("EmitCallWithIC"); | 2320 ASM_LOCATION("EmitCallWithIC"); |
2322 // Code common for calls using the IC. | 2321 |
| 2322 Expression* callee = expr->expression(); |
2323 ZoneList<Expression*>* args = expr->arguments(); | 2323 ZoneList<Expression*>* args = expr->arguments(); |
2324 int arg_count = args->length(); | 2324 int arg_count = args->length(); |
2325 { PreservePositionScope scope(masm()->positions_recorder()); | 2325 |
2326 for (int i = 0; i < arg_count; i++) { | 2326 CallFunctionFlags flags; |
2327 VisitForStackValue(args->at(i)); | 2327 // Get the target function. |
| 2328 if (callee->IsVariableProxy()) { |
| 2329 { StackValueContext context(this); |
| 2330 EmitVariableLoad(callee->AsVariableProxy()); |
| 2331 PrepareForBailout(callee, NO_REGISTERS); |
2328 } | 2332 } |
2329 __ Mov(x2, Operand(name)); | 2333 // Push undefined as receiver. This is patched in the method prologue if it |
| 2334 // is a classic mode method. |
| 2335 __ Push(isolate()->factory()->undefined_value()); |
| 2336 flags = NO_CALL_FUNCTION_FLAGS; |
| 2337 } else { |
| 2338 // Load the function from the receiver. |
| 2339 ASSERT(callee->IsProperty()); |
| 2340 __ Peek(x0, 0); |
| 2341 EmitNamedPropertyLoad(callee->AsProperty()); |
| 2342 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); |
| 2343 // Push the target function under the receiver. |
| 2344 __ Pop(x10); |
| 2345 __ Push(x0, x10); |
| 2346 flags = CALL_AS_METHOD; |
2330 } | 2347 } |
2331 // Record source position for debugger. | |
2332 SetSourcePosition(expr->position()); | |
2333 // Call the IC initialization code. | |
2334 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count); | |
2335 TypeFeedbackId ast_id = mode == CONTEXTUAL | |
2336 ? TypeFeedbackId::None() | |
2337 : expr->CallFeedbackId(); | |
2338 CallIC(ic, mode, ast_id); | |
2339 RecordJSReturnSite(expr); | |
2340 // Restore context register. | |
2341 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | |
2342 context()->Plug(x0); | |
2343 } | |
2344 | 2348 |
2345 | 2349 // Load the arguments. |
2346 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, | |
2347 Expression* key) { | |
2348 // Load the key. | |
2349 VisitForAccumulatorValue(key); | |
2350 // Load the key. | |
2351 | |
2352 // Swap the name of the function and the receiver on the stack to follow | |
2353 // the calling convention for call ICs. | |
2354 __ Pop(x1); | |
2355 __ Push(x0, x1); | |
2356 | |
2357 // Code common for calls using the IC. | |
2358 ZoneList<Expression*>* args = expr->arguments(); | |
2359 int arg_count = args->length(); | |
2360 { PreservePositionScope scope(masm()->positions_recorder()); | 2350 { PreservePositionScope scope(masm()->positions_recorder()); |
2361 for (int i = 0; i < arg_count; i++) { | 2351 for (int i = 0; i < arg_count; i++) { |
2362 VisitForStackValue(args->at(i)); | 2352 VisitForStackValue(args->at(i)); |
2363 } | 2353 } |
2364 } | 2354 } |
| 2355 |
2365 // Record source position for debugger. | 2356 // Record source position for debugger. |
2366 SetSourcePosition(expr->position()); | 2357 SetSourcePosition(expr->position()); |
2367 // Call the IC initialization code. | 2358 CallFunctionStub stub(arg_count, flags); |
2368 Handle<Code> ic = | 2359 __ Peek(x1, (arg_count + 1) * kPointerSize); |
2369 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count); | 2360 __ CallStub(&stub); |
2370 __ Peek(x2, (arg_count + 1) * kXRegSizeInBytes); // Key. | 2361 |
2371 CallIC(ic, NOT_CONTEXTUAL, expr->CallFeedbackId()); | 2362 RecordJSReturnSite(expr); |
| 2363 |
| 2364 // Restore context register. |
| 2365 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2366 |
| 2367 context()->DropAndPlug(1, x0); |
| 2368 } |
| 2369 |
| 2370 |
| 2371 // Code common for calls using the IC. |
| 2372 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, |
| 2373 Expression* key) { |
| 2374 // Load the key. |
| 2375 VisitForAccumulatorValue(key); |
| 2376 |
| 2377 Expression* callee = expr->expression(); |
| 2378 ZoneList<Expression*>* args = expr->arguments(); |
| 2379 int arg_count = args->length(); |
| 2380 |
| 2381 // Load the function from the receiver. |
| 2382 ASSERT(callee->IsProperty()); |
| 2383 __ Peek(x1, 0); |
| 2384 EmitKeyedPropertyLoad(callee->AsProperty()); |
| 2385 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); |
| 2386 |
| 2387 // Push the target function under the receiver. |
| 2388 __ Pop(x10); |
| 2389 __ Push(x0, x10); |
| 2390 |
| 2391 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2392 for (int i = 0; i < arg_count; i++) { |
| 2393 VisitForStackValue(args->at(i)); |
| 2394 } |
| 2395 } |
| 2396 |
| 2397 // Record source position for debugger. |
| 2398 SetSourcePosition(expr->position()); |
| 2399 CallFunctionStub stub(arg_count, CALL_AS_METHOD); |
| 2400 __ Peek(x1, (arg_count + 1) * kPointerSize); |
| 2401 __ CallStub(&stub); |
| 2402 |
2372 RecordJSReturnSite(expr); | 2403 RecordJSReturnSite(expr); |
2373 // Restore context register. | 2404 // Restore context register. |
2374 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2405 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
2375 context()->DropAndPlug(1, x0); // Drop the key still on the stack. | 2406 |
| 2407 context()->DropAndPlug(1, x0); |
2376 } | 2408 } |
2377 | 2409 |
2378 | 2410 |
2379 void FullCodeGenerator::EmitCallWithStub(Call* expr) { | 2411 void FullCodeGenerator::EmitCallWithStub(Call* expr) { |
2380 // Code common for calls using the call stub. | 2412 // Code common for calls using the call stub. |
2381 ZoneList<Expression*>* args = expr->arguments(); | 2413 ZoneList<Expression*>* args = expr->arguments(); |
2382 int arg_count = args->length(); | 2414 int arg_count = args->length(); |
2383 { PreservePositionScope scope(masm()->positions_recorder()); | 2415 { PreservePositionScope scope(masm()->positions_recorder()); |
2384 for (int i = 0; i < arg_count; i++) { | 2416 for (int i = 0; i < arg_count; i++) { |
2385 VisitForStackValue(args->at(i)); | 2417 VisitForStackValue(args->at(i)); |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2483 // Call the evaluated function. | 2515 // Call the evaluated function. |
2484 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS); | 2516 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS); |
2485 __ Peek(x1, (arg_count + 1) * kXRegSizeInBytes); | 2517 __ Peek(x1, (arg_count + 1) * kXRegSizeInBytes); |
2486 __ CallStub(&stub); | 2518 __ CallStub(&stub); |
2487 RecordJSReturnSite(expr); | 2519 RecordJSReturnSite(expr); |
2488 // Restore context register. | 2520 // Restore context register. |
2489 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2521 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
2490 context()->DropAndPlug(1, x0); | 2522 context()->DropAndPlug(1, x0); |
2491 | 2523 |
2492 } else if (call_type == Call::GLOBAL_CALL) { | 2524 } else if (call_type == Call::GLOBAL_CALL) { |
2493 // Push global object as receiver for the call IC. | 2525 EmitCallWithIC(expr); |
2494 __ Ldr(x10, GlobalObjectMemOperand()); | |
2495 __ Push(x10); | |
2496 VariableProxy* proxy = callee->AsVariableProxy(); | |
2497 EmitCallWithIC(expr, proxy->name(), CONTEXTUAL); | |
2498 | 2526 |
2499 } else if (call_type == Call::LOOKUP_SLOT_CALL) { | 2527 } else if (call_type == Call::LOOKUP_SLOT_CALL) { |
2500 // Call to a lookup slot (dynamically introduced variable). | 2528 // Call to a lookup slot (dynamically introduced variable). |
2501 VariableProxy* proxy = callee->AsVariableProxy(); | 2529 VariableProxy* proxy = callee->AsVariableProxy(); |
2502 Label slow, done; | 2530 Label slow, done; |
2503 | 2531 |
2504 { PreservePositionScope scope(masm()->positions_recorder()); | 2532 { PreservePositionScope scope(masm()->positions_recorder()); |
2505 // Generate code for loading from variables potentially shadowed | 2533 // Generate code for loading from variables potentially shadowed |
2506 // by eval-introduced variables. | 2534 // by eval-introduced variables. |
2507 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); | 2535 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); |
(...skipping 26 matching lines...) Expand all Loading... |
2534 | 2562 |
2535 // The receiver is either the global receiver or an object found | 2563 // The receiver is either the global receiver or an object found |
2536 // by LoadContextSlot. | 2564 // by LoadContextSlot. |
2537 EmitCallWithStub(expr); | 2565 EmitCallWithStub(expr); |
2538 } else if (call_type == Call::PROPERTY_CALL) { | 2566 } else if (call_type == Call::PROPERTY_CALL) { |
2539 Property* property = callee->AsProperty(); | 2567 Property* property = callee->AsProperty(); |
2540 { PreservePositionScope scope(masm()->positions_recorder()); | 2568 { PreservePositionScope scope(masm()->positions_recorder()); |
2541 VisitForStackValue(property->obj()); | 2569 VisitForStackValue(property->obj()); |
2542 } | 2570 } |
2543 if (property->key()->IsPropertyName()) { | 2571 if (property->key()->IsPropertyName()) { |
2544 EmitCallWithIC(expr, | 2572 EmitCallWithIC(expr); |
2545 property->key()->AsLiteral()->value(), | |
2546 NOT_CONTEXTUAL); | |
2547 } else { | 2573 } else { |
2548 EmitKeyedCallWithIC(expr, property->key()); | 2574 EmitKeyedCallWithIC(expr, property->key()); |
2549 } | 2575 } |
2550 | 2576 |
2551 } else { | 2577 } else { |
2552 ASSERT(call_type == Call::OTHER_CALL); | 2578 ASSERT(call_type == Call::OTHER_CALL); |
2553 // Call to an arbitrary expression not handled specially above. | 2579 // Call to an arbitrary expression not handled specially above. |
2554 { PreservePositionScope scope(masm()->positions_recorder()); | 2580 { PreservePositionScope scope(masm()->positions_recorder()); |
2555 VisitForStackValue(callee); | 2581 VisitForStackValue(callee); |
2556 } | 2582 } |
(...skipping 996 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3553 | 3579 |
3554 // Call runtime to perform the lookup. | 3580 // Call runtime to perform the lookup. |
3555 __ Push(cache, key); | 3581 __ Push(cache, key); |
3556 __ CallRuntime(Runtime::kGetFromCache, 2); | 3582 __ CallRuntime(Runtime::kGetFromCache, 2); |
3557 | 3583 |
3558 __ Bind(&done); | 3584 __ Bind(&done); |
3559 context()->Plug(x0); | 3585 context()->Plug(x0); |
3560 } | 3586 } |
3561 | 3587 |
3562 | 3588 |
3563 void FullCodeGenerator::EmitIsRegExpEquivalent(CallRuntime* expr) { | |
3564 ASM_UNIMPLEMENTED("EmitIsRegExpEquivalent has not been tested"); | |
3565 | |
3566 ZoneList<Expression*>* args = expr->arguments(); | |
3567 ASSERT_EQ(2, args->length()); | |
3568 | |
3569 Register right = x2; | |
3570 Register left = x1; | |
3571 | |
3572 VisitForStackValue(args->at(0)); | |
3573 VisitForAccumulatorValue(args->at(1)); | |
3574 __ Pop(left); | |
3575 __ Mov(right, x0); | |
3576 | |
3577 // Speculatively set result to true. | |
3578 Register result = x0; | |
3579 __ LoadRoot(result, Heap::kTrueValueRootIndex); | |
3580 | |
3581 Label fail, ok; | |
3582 __ Cmp(left, right); | |
3583 __ B(eq, &ok); | |
3584 | |
3585 // Fail if either is a non-HeapObject. | |
3586 __ JumpIfEitherSmi(left, right, &fail); | |
3587 | |
3588 Register left_map = x10; | |
3589 __ Ldr(left_map, FieldMemOperand(left, HeapObject::kMapOffset)); | |
3590 __ Ldrb(x11, FieldMemOperand(left_map, Map::kInstanceTypeOffset)); | |
3591 __ Cmp(x11, JS_REGEXP_TYPE); | |
3592 __ B(ne, &fail); | |
3593 | |
3594 Register right_map = x11; | |
3595 __ Ldr(right_map, FieldMemOperand(right, HeapObject::kMapOffset)); | |
3596 __ Cmp(left_map, right_map); | |
3597 __ B(ne, &fail); | |
3598 | |
3599 __ Ldr(x10, FieldMemOperand(left, JSRegExp::kDataOffset)); | |
3600 __ Ldr(x11, FieldMemOperand(right, JSRegExp::kDataOffset)); | |
3601 __ Cmp(x10, x11); | |
3602 __ B(eq, &ok); | |
3603 | |
3604 __ Bind(&fail); | |
3605 __ LoadRoot(result, Heap::kFalseValueRootIndex); | |
3606 | |
3607 __ Bind(&ok); | |
3608 context()->Plug(result); | |
3609 } | |
3610 | |
3611 | |
3612 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { | 3589 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { |
3613 ZoneList<Expression*>* args = expr->arguments(); | 3590 ZoneList<Expression*>* args = expr->arguments(); |
3614 VisitForAccumulatorValue(args->at(0)); | 3591 VisitForAccumulatorValue(args->at(0)); |
3615 | 3592 |
3616 Label materialize_true, materialize_false; | 3593 Label materialize_true, materialize_false; |
3617 Label* if_true = NULL; | 3594 Label* if_true = NULL; |
3618 Label* if_false = NULL; | 3595 Label* if_false = NULL; |
3619 Label* fall_through = NULL; | 3596 Label* fall_through = NULL; |
3620 context()->PrepareTest(&materialize_true, &materialize_false, | 3597 context()->PrepareTest(&materialize_true, &materialize_false, |
3621 &if_true, &if_false, &fall_through); | 3598 &if_true, &if_false, &fall_through); |
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3862 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 3839 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
3863 Handle<String> name = expr->name(); | 3840 Handle<String> name = expr->name(); |
3864 if (name->length() > 0 && name->Get(0) == '_') { | 3841 if (name->length() > 0 && name->Get(0) == '_') { |
3865 Comment cmnt(masm_, "[ InlineRuntimeCall"); | 3842 Comment cmnt(masm_, "[ InlineRuntimeCall"); |
3866 EmitInlineRuntimeCall(expr); | 3843 EmitInlineRuntimeCall(expr); |
3867 return; | 3844 return; |
3868 } | 3845 } |
3869 | 3846 |
3870 Comment cmnt(masm_, "[ CallRunTime"); | 3847 Comment cmnt(masm_, "[ CallRunTime"); |
3871 ZoneList<Expression*>* args = expr->arguments(); | 3848 ZoneList<Expression*>* args = expr->arguments(); |
| 3849 int arg_count = args->length(); |
3872 | 3850 |
3873 if (expr->is_jsruntime()) { | 3851 if (expr->is_jsruntime()) { |
3874 // Prepare for calling JS runtime function. | 3852 // Push the builtins object as the receiver. |
3875 __ Ldr(x10, GlobalObjectMemOperand()); | 3853 __ Ldr(x10, GlobalObjectMemOperand()); |
3876 __ Ldr(x11, FieldMemOperand(x10, GlobalObject::kBuiltinsOffset)); | 3854 __ Ldr(x0, FieldMemOperand(x10, GlobalObject::kBuiltinsOffset)); |
3877 __ Push(x11); | 3855 __ Push(x0); |
3878 } | |
3879 | 3856 |
3880 int arg_count = args->length(); | 3857 // Load the function from the receiver. |
3881 for (int i = 0; i < arg_count; i++) { | 3858 __ Mov(x2, Operand(name)); |
3882 VisitForStackValue(args->at(i)); | 3859 CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); |
3883 } | |
3884 | 3860 |
3885 if (expr->is_jsruntime()) { | 3861 // Push the target function under the receiver. |
3886 // Call the JS runtime function. | 3862 __ Pop(x10); |
3887 __ Mov(x2, Operand(expr->name())); | 3863 __ Push(x0, x10); |
3888 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count); | 3864 |
3889 CallIC(ic, NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); | 3865 int arg_count = args->length(); |
| 3866 for (int i = 0; i < arg_count; i++) { |
| 3867 VisitForStackValue(args->at(i)); |
| 3868 } |
| 3869 |
| 3870 // Record source position of the IC call. |
| 3871 SetSourcePosition(expr->position()); |
| 3872 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS); |
| 3873 __ Peek(x1, (arg_count + 1) * kPointerSize); |
| 3874 __ CallStub(&stub); |
| 3875 |
3890 // Restore context register. | 3876 // Restore context register. |
3891 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 3877 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 3878 |
| 3879 context()->DropAndPlug(1, x0); |
3892 } else { | 3880 } else { |
| 3881 // Push the arguments ("left-to-right"). |
| 3882 for (int i = 0; i < arg_count; i++) { |
| 3883 VisitForStackValue(args->at(i)); |
| 3884 } |
| 3885 |
3893 // Call the C runtime function. | 3886 // Call the C runtime function. |
3894 __ CallRuntime(expr->function(), arg_count); | 3887 __ CallRuntime(expr->function(), arg_count); |
| 3888 context()->Plug(x0); |
3895 } | 3889 } |
3896 | |
3897 context()->Plug(x0); | |
3898 } | 3890 } |
3899 | 3891 |
3900 | 3892 |
3901 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 3893 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
3902 switch (expr->op()) { | 3894 switch (expr->op()) { |
3903 case Token::DELETE: { | 3895 case Token::DELETE: { |
3904 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 3896 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
3905 Property* property = expr->expression()->AsProperty(); | 3897 Property* property = expr->expression()->AsProperty(); |
3906 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 3898 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
3907 | 3899 |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4258 Split(eq, if_true, if_false, fall_through); | 4250 Split(eq, if_true, if_false, fall_through); |
4259 } else if (check->Equals(isolate()->heap()->string_string())) { | 4251 } else if (check->Equals(isolate()->heap()->string_string())) { |
4260 ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof string_string"); | 4252 ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof string_string"); |
4261 __ JumpIfSmi(x0, if_false); | 4253 __ JumpIfSmi(x0, if_false); |
4262 // Check for undetectable objects => false. | 4254 // Check for undetectable objects => false. |
4263 __ JumpIfObjectType(x0, x0, x1, FIRST_NONSTRING_TYPE, if_false, ge); | 4255 __ JumpIfObjectType(x0, x0, x1, FIRST_NONSTRING_TYPE, if_false, ge); |
4264 __ Ldrb(x1, FieldMemOperand(x0, Map::kBitFieldOffset)); | 4256 __ Ldrb(x1, FieldMemOperand(x0, Map::kBitFieldOffset)); |
4265 __ TestAndSplit(x1, 1 << Map::kIsUndetectable, if_true, if_false, | 4257 __ TestAndSplit(x1, 1 << Map::kIsUndetectable, if_true, if_false, |
4266 fall_through); | 4258 fall_through); |
4267 } else if (check->Equals(isolate()->heap()->symbol_string())) { | 4259 } else if (check->Equals(isolate()->heap()->symbol_string())) { |
| 4260 ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof symbol_string"); |
4268 __ JumpIfSmi(x0, if_false); | 4261 __ JumpIfSmi(x0, if_false); |
4269 __ CompareObjectType(x0, x0, x1, SYMBOL_TYPE); | 4262 __ CompareObjectType(x0, x0, x1, SYMBOL_TYPE); |
4270 Split(eq, if_true, if_false, fall_through); | 4263 Split(eq, if_true, if_false, fall_through); |
4271 } else if (check->Equals(isolate()->heap()->boolean_string())) { | 4264 } else if (check->Equals(isolate()->heap()->boolean_string())) { |
4272 ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof boolean_string"); | 4265 ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof boolean_string"); |
4273 __ JumpIfRoot(x0, Heap::kTrueValueRootIndex, if_true); | 4266 __ JumpIfRoot(x0, Heap::kTrueValueRootIndex, if_true); |
4274 __ CompareRoot(x0, Heap::kFalseValueRootIndex); | 4267 __ CompareRoot(x0, Heap::kFalseValueRootIndex); |
4275 Split(eq, if_true, if_false, fall_through); | 4268 Split(eq, if_true, if_false, fall_through); |
4276 } else if (FLAG_harmony_typeof && | 4269 } else if (FLAG_harmony_typeof && |
4277 check->Equals(isolate()->heap()->null_string())) { | 4270 check->Equals(isolate()->heap()->null_string())) { |
| 4271 ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof null_string"); |
4278 __ CompareRoot(x0, Heap::kNullValueRootIndex); | 4272 __ CompareRoot(x0, Heap::kNullValueRootIndex); |
4279 Split(eq, if_true, if_false, fall_through); | 4273 Split(eq, if_true, if_false, fall_through); |
4280 } else if (check->Equals(isolate()->heap()->undefined_string())) { | 4274 } else if (check->Equals(isolate()->heap()->undefined_string())) { |
4281 ASM_LOCATION( | 4275 ASM_LOCATION( |
4282 "FullCodeGenerator::EmitLiteralCompareTypeof undefined_string"); | 4276 "FullCodeGenerator::EmitLiteralCompareTypeof undefined_string"); |
4283 __ JumpIfRoot(x0, Heap::kUndefinedValueRootIndex, if_true); | 4277 __ JumpIfRoot(x0, Heap::kUndefinedValueRootIndex, if_true); |
4284 __ JumpIfSmi(x0, if_false); | 4278 __ JumpIfSmi(x0, if_false); |
4285 // Check for undetectable objects => true. | 4279 // Check for undetectable objects => true. |
4286 __ Ldr(x0, FieldMemOperand(x0, HeapObject::kMapOffset)); | 4280 __ Ldr(x0, FieldMemOperand(x0, HeapObject::kMapOffset)); |
4287 __ Ldrb(x1, FieldMemOperand(x0, Map::kBitFieldOffset)); | 4281 __ Ldrb(x1, FieldMemOperand(x0, Map::kBitFieldOffset)); |
(...skipping 19 matching lines...) Expand all Loading... |
4307 if_false, lt); | 4301 if_false, lt); |
4308 __ CompareInstanceType(map, x11, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); | 4302 __ CompareInstanceType(map, x11, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); |
4309 __ B(gt, if_false); | 4303 __ B(gt, if_false); |
4310 // Check for undetectable objects => false. | 4304 // Check for undetectable objects => false. |
4311 __ Ldrb(x10, FieldMemOperand(map, Map::kBitFieldOffset)); | 4305 __ Ldrb(x10, FieldMemOperand(map, Map::kBitFieldOffset)); |
4312 | 4306 |
4313 __ TestAndSplit(x10, 1 << Map::kIsUndetectable, if_true, if_false, | 4307 __ TestAndSplit(x10, 1 << Map::kIsUndetectable, if_true, if_false, |
4314 fall_through); | 4308 fall_through); |
4315 | 4309 |
4316 } else { | 4310 } else { |
| 4311 ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof other"); |
4317 if (if_false != fall_through) __ B(if_false); | 4312 if (if_false != fall_through) __ B(if_false); |
4318 } | 4313 } |
4319 context()->Plug(if_true, if_false); | 4314 context()->Plug(if_true, if_false); |
4320 } | 4315 } |
4321 | 4316 |
4322 | 4317 |
4323 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 4318 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
4324 Comment cmnt(masm_, "[ CompareOperation"); | 4319 Comment cmnt(masm_, "[ CompareOperation"); |
4325 SetSourcePosition(expr->position()); | 4320 SetSourcePosition(expr->position()); |
4326 | 4321 |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4501 | 4496 |
4502 Label l_catch, l_try, l_suspend, l_continuation, l_resume; | 4497 Label l_catch, l_try, l_suspend, l_continuation, l_resume; |
4503 Label l_next, l_call, l_loop; | 4498 Label l_next, l_call, l_loop; |
4504 // Initial send value is undefined. | 4499 // Initial send value is undefined. |
4505 __ LoadRoot(x0, Heap::kUndefinedValueRootIndex); | 4500 __ LoadRoot(x0, Heap::kUndefinedValueRootIndex); |
4506 __ B(&l_next); | 4501 __ B(&l_next); |
4507 | 4502 |
4508 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; } | 4503 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; } |
4509 __ Bind(&l_catch); | 4504 __ Bind(&l_catch); |
4510 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos())); | 4505 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos())); |
4511 __ LoadRoot(x2, Heap::kthrow_stringRootIndex); // "throw" | 4506 __ LoadRoot(x2, Heap::kthrow_stringRootIndex); // "throw" |
4512 __ Peek(x3, 1 * kPointerSize); // iter | 4507 __ Peek(x3, 1 * kPointerSize); // iter |
4513 __ Push(x3); // iter | 4508 __ Push(x2, x3, x0); // "throw", iter, except |
4514 __ Push(x0); // exception | |
4515 __ B(&l_call); | 4509 __ B(&l_call); |
4516 | 4510 |
4517 // try { received = %yield result } | 4511 // try { received = %yield result } |
4518 // Shuffle the received result above a try handler and yield it without | 4512 // Shuffle the received result above a try handler and yield it without |
4519 // re-boxing. | 4513 // re-boxing. |
4520 __ Bind(&l_try); | 4514 __ Bind(&l_try); |
4521 __ Pop(x0); // result | 4515 __ Pop(x0); // result |
4522 __ PushTryHandler(StackHandler::CATCH, expr->index()); | 4516 __ PushTryHandler(StackHandler::CATCH, expr->index()); |
4523 const int handler_size = StackHandlerConstants::kSize; | 4517 const int handler_size = StackHandlerConstants::kSize; |
4524 __ Push(x0); // result | 4518 __ Push(x0); // result |
(...skipping 18 matching lines...) Expand all Loading... |
4543 kLRHasBeenSaved, kDontSaveFPRegs); | 4537 kLRHasBeenSaved, kDontSaveFPRegs); |
4544 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); | 4538 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); |
4545 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 4539 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
4546 __ Pop(x0); // result | 4540 __ Pop(x0); // result |
4547 EmitReturnSequence(); | 4541 EmitReturnSequence(); |
4548 __ Bind(&l_resume); // received in x0 | 4542 __ Bind(&l_resume); // received in x0 |
4549 __ PopTryHandler(); | 4543 __ PopTryHandler(); |
4550 | 4544 |
4551 // receiver = iter; f = 'next'; arg = received; | 4545 // receiver = iter; f = 'next'; arg = received; |
4552 __ Bind(&l_next); | 4546 __ Bind(&l_next); |
4553 __ LoadRoot(x2, Heap::knext_stringRootIndex); // "next" | 4547 __ LoadRoot(x2, Heap::knext_stringRootIndex); // "next" |
4554 __ Peek(x3, 1 * kPointerSize); // iter | 4548 __ Peek(x3, 1 * kPointerSize); // iter |
4555 __ Push(x3); // iter | 4549 __ Push(x2, x3, x0); // "next", iter, received |
4556 __ Push(x0); // received | |
4557 | 4550 |
4558 // result = receiver[f](arg); | 4551 // result = receiver[f](arg); |
4559 __ Bind(&l_call); | 4552 __ Bind(&l_call); |
4560 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(1); | 4553 __ Peek(x1, 1 * kPointerSize); |
4561 CallIC(ic); | 4554 __ Peek(x0, 2 * kPointerSize); |
| 4555 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 4556 CallIC(ic, NOT_CONTEXTUAL, TypeFeedbackId::None()); |
| 4557 __ Mov(x1, x0); |
| 4558 __ Poke(x1, 2 * kPointerSize); |
| 4559 CallFunctionStub stub(1, CALL_AS_METHOD); |
| 4560 __ CallStub(&stub); |
| 4561 |
4562 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 4562 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 4563 __ Drop(1); // The function is still on the stack; drop it. |
4563 | 4564 |
4564 // if (!result.done) goto l_try; | 4565 // if (!result.done) goto l_try; |
4565 __ Bind(&l_loop); | 4566 __ Bind(&l_loop); |
4566 __ Push(x0); // save result | 4567 __ Push(x0); // save result |
4567 __ LoadRoot(x2, Heap::kdone_stringRootIndex); // "done" | 4568 __ LoadRoot(x2, Heap::kdone_stringRootIndex); // "done" |
4568 CallLoadIC(NOT_CONTEXTUAL); // result.done in x0 | 4569 CallLoadIC(NOT_CONTEXTUAL); // result.done in x0 |
4569 // The ToBooleanStub argument (result.done) is in x0. | 4570 // The ToBooleanStub argument (result.done) is in x0. |
4570 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); | 4571 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); |
4571 CallIC(bool_ic); | 4572 CallIC(bool_ic); |
4572 __ Cbz(x0, &l_try); | 4573 __ Cbz(x0, &l_try); |
(...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5009 return previous_; | 5010 return previous_; |
5010 } | 5011 } |
5011 | 5012 |
5012 | 5013 |
5013 #undef __ | 5014 #undef __ |
5014 | 5015 |
5015 | 5016 |
5016 } } // namespace v8::internal | 5017 } } // namespace v8::internal |
5017 | 5018 |
5018 #endif // V8_TARGET_ARCH_A64 | 5019 #endif // V8_TARGET_ARCH_A64 |
OLD | NEW |