OLD | NEW |
---|---|
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 2937 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2948 } | 2948 } |
2949 if (lookup->type() != NORMAL) { | 2949 if (lookup->type() != NORMAL) { |
2950 BAILOUT("global variable has accessors"); | 2950 BAILOUT("global variable has accessors"); |
2951 } | 2951 } |
2952 if (is_store && lookup->IsReadOnly()) { | 2952 if (is_store && lookup->IsReadOnly()) { |
2953 BAILOUT("read-only global variable"); | 2953 BAILOUT("read-only global variable"); |
2954 } | 2954 } |
2955 } | 2955 } |
2956 | 2956 |
2957 | 2957 |
2958 HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) { | |
2959 ASSERT(var->IsContextSlot()); | |
2960 HInstruction* context = new HContext; | |
2961 AddInstruction(context); | |
2962 int length = graph()->info()->scope()->ContextChainLength(var->scope()); | |
2963 while (length-- > 0) { | |
2964 context = new HOuterContext(context); | |
2965 AddInstruction(context); | |
2966 } | |
2967 return context; | |
2968 } | |
2969 | |
2970 | |
2958 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { | 2971 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
2959 Variable* variable = expr->AsVariable(); | 2972 Variable* variable = expr->AsVariable(); |
2960 if (variable == NULL) { | 2973 if (variable == NULL) { |
2961 BAILOUT("reference to rewritten variable"); | 2974 BAILOUT("reference to rewritten variable"); |
2962 } else if (variable->IsStackAllocated()) { | 2975 } else if (variable->IsStackAllocated()) { |
2963 if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) { | 2976 if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) { |
2964 BAILOUT("unsupported context for arguments object"); | 2977 BAILOUT("unsupported context for arguments object"); |
2965 } | 2978 } |
2966 ast_context()->ReturnValue(environment()->Lookup(variable)); | 2979 ast_context()->ReturnValue(environment()->Lookup(variable)); |
2967 } else if (variable->IsContextSlot()) { | 2980 } else if (variable->IsContextSlot()) { |
2968 if (variable->mode() == Variable::CONST) { | 2981 if (variable->mode() == Variable::CONST) { |
2969 BAILOUT("reference to const context slot"); | 2982 BAILOUT("reference to const context slot"); |
2970 } | 2983 } |
2971 Slot* slot = variable->AsSlot(); | 2984 HValue* context = BuildContextChainWalk(variable); |
2972 CompilationInfo* info = graph()->info(); | 2985 int index = variable->AsSlot()->index(); |
2973 int context_chain_length = info->function()->scope()-> | 2986 HLoadContextSlot* instr = new HLoadContextSlot(context, index); |
2974 ContextChainLength(slot->var()->scope()); | |
2975 ASSERT(context_chain_length >= 0); | |
2976 // TODO(antonm): if slot's value is not modified by closures, instead | |
antonm
2011/02/03 13:14:30
may we keep this TODO?
| |
2977 // of reading it out of context, we could just embed the value as | |
2978 // a constant. | |
2979 HLoadContextSlot* instr = | |
2980 new HLoadContextSlot(context_chain_length, slot->index()); | |
2981 ast_context()->ReturnInstruction(instr, expr->id()); | 2987 ast_context()->ReturnInstruction(instr, expr->id()); |
2982 } else if (variable->is_global()) { | 2988 } else if (variable->is_global()) { |
2983 LookupResult lookup; | 2989 LookupResult lookup; |
2984 LookupGlobalPropertyCell(variable, &lookup, false); | 2990 LookupGlobalPropertyCell(variable, &lookup, false); |
2985 CHECK_BAILOUT; | 2991 CHECK_BAILOUT; |
2986 | 2992 |
2987 Handle<GlobalObject> global(graph()->info()->global_object()); | 2993 Handle<GlobalObject> global(graph()->info()->global_object()); |
2988 // TODO(3039103): Handle global property load through an IC call when access | 2994 // TODO(3039103): Handle global property load through an IC call when access |
2989 // checks are enabled. | 2995 // checks are enabled. |
2990 if (global->IsAccessCheckNeeded()) { | 2996 if (global->IsAccessCheckNeeded()) { |
(...skipping 517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3508 | 3514 |
3509 if (expr->is_compound()) { | 3515 if (expr->is_compound()) { |
3510 HandleCompoundAssignment(expr); | 3516 HandleCompoundAssignment(expr); |
3511 return; | 3517 return; |
3512 } | 3518 } |
3513 | 3519 |
3514 if (var != NULL) { | 3520 if (var != NULL) { |
3515 if (proxy->IsArguments()) BAILOUT("assignment to arguments"); | 3521 if (proxy->IsArguments()) BAILOUT("assignment to arguments"); |
3516 | 3522 |
3517 // Handle the assignment. | 3523 // Handle the assignment. |
3518 if (var->is_global()) { | 3524 if (var->IsStackAllocated()) { |
3525 HValue* value = NULL; | |
3526 // Handle stack-allocated variables on the right-hand side directly. | |
3527 // We do not allow the arguments object to occur in a context where it | |
3528 // may escape, but assignments to stack-allocated locals are | |
3529 // permitted. Handling such assignments here bypasses the check for | |
3530 // the arguments object in VisitVariableProxy. | |
3531 Variable* rhs_var = expr->value()->AsVariableProxy()->AsVariable(); | |
3532 if (rhs_var != NULL && rhs_var->IsStackAllocated()) { | |
3533 value = environment()->Lookup(rhs_var); | |
3534 } else { | |
3535 VISIT_FOR_VALUE(expr->value()); | |
3536 value = Pop(); | |
3537 } | |
3538 Bind(var, value); | |
3539 ast_context()->ReturnValue(value); | |
3540 | |
3541 } else if (var->IsContextSlot() && var->mode() != Variable::CONST) { | |
3542 VISIT_FOR_VALUE(expr->value()); | |
3543 HValue* context = BuildContextChainWalk(var); | |
3544 int index = var->AsSlot()->index(); | |
3545 HStoreContextSlot* instr = new HStoreContextSlot(context, index, Top()); | |
3546 AddInstruction(instr); | |
3547 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | |
3548 ast_context()->ReturnValue(Pop()); | |
3549 | |
3550 } else if (var->is_global()) { | |
3519 VISIT_FOR_VALUE(expr->value()); | 3551 VISIT_FOR_VALUE(expr->value()); |
3520 HandleGlobalVariableAssignment(var, | 3552 HandleGlobalVariableAssignment(var, |
3521 Top(), | 3553 Top(), |
3522 expr->position(), | 3554 expr->position(), |
3523 expr->AssignmentId()); | 3555 expr->AssignmentId()); |
3524 } else if (var->IsStackAllocated()) { | 3556 ast_context()->ReturnValue(Pop()); |
3525 // We allow reference to the arguments object only in assignemtns | 3557 |
3526 // to local variables to make sure that the arguments object does | |
3527 // not escape and is not modified. | |
3528 VariableProxy* rhs = expr->value()->AsVariableProxy(); | |
3529 if (rhs != NULL && | |
3530 rhs->var()->IsStackAllocated() && | |
3531 environment()->Lookup(rhs->var())->CheckFlag(HValue::kIsArguments)) { | |
3532 Push(environment()->Lookup(rhs->var())); | |
3533 } else { | |
3534 VISIT_FOR_VALUE(expr->value()); | |
3535 } | |
3536 Bind(proxy->var(), Top()); | |
3537 } else { | 3558 } else { |
3538 BAILOUT("Assigning to no non-stack-allocated/non-global variable"); | 3559 BAILOUT("assignment to LOOKUP or const CONTEXT variable"); |
3539 } | 3560 } |
3540 // Return the value. | |
3541 ast_context()->ReturnValue(Pop()); | |
3542 | 3561 |
3543 } else if (prop != NULL) { | 3562 } else if (prop != NULL) { |
3544 HandlePropertyAssignment(expr); | 3563 HandlePropertyAssignment(expr); |
3545 } else { | 3564 } else { |
3546 BAILOUT("unsupported invalid lhs"); | 3565 BAILOUT("invalid left-hand side in assignment"); |
3547 } | 3566 } |
3548 } | 3567 } |
3549 | 3568 |
3550 | 3569 |
3551 void HGraphBuilder::VisitThrow(Throw* expr) { | 3570 void HGraphBuilder::VisitThrow(Throw* expr) { |
3552 // We don't optimize functions with invalid left-hand sides in | 3571 // We don't optimize functions with invalid left-hand sides in |
3553 // assignments, count operations, or for-in. Consequently throw can | 3572 // assignments, count operations, or for-in. Consequently throw can |
3554 // currently only occur in an effect context. | 3573 // currently only occur in an effect context. |
3555 ASSERT(ast_context()->IsEffect()); | 3574 ASSERT(ast_context()->IsEffect()); |
3556 VISIT_FOR_VALUE(expr->exception()); | 3575 VISIT_FOR_VALUE(expr->exception()); |
(...skipping 858 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4415 // access check is not enabled we assume that the function will not change | 4434 // access check is not enabled we assume that the function will not change |
4416 // and generate optimized code for calling the function. | 4435 // and generate optimized code for calling the function. |
4417 CompilationInfo* info = graph()->info(); | 4436 CompilationInfo* info = graph()->info(); |
4418 bool known_global_function = info->has_global_object() && | 4437 bool known_global_function = info->has_global_object() && |
4419 !info->global_object()->IsAccessCheckNeeded() && | 4438 !info->global_object()->IsAccessCheckNeeded() && |
4420 expr->ComputeGlobalTarget(Handle<GlobalObject>(info->global_object()), | 4439 expr->ComputeGlobalTarget(Handle<GlobalObject>(info->global_object()), |
4421 var->name()); | 4440 var->name()); |
4422 if (known_global_function) { | 4441 if (known_global_function) { |
4423 // Push the global object instead of the global receiver because | 4442 // Push the global object instead of the global receiver because |
4424 // code generated by the full code generator expects it. | 4443 // code generated by the full code generator expects it. |
4425 PushAndAdd(new HGlobalObject); | 4444 HContext* context = new HContext; |
4445 HGlobalObject* global_object = new HGlobalObject(context); | |
4446 AddInstruction(context); | |
4447 PushAndAdd(global_object); | |
4426 VisitArgumentList(expr->arguments()); | 4448 VisitArgumentList(expr->arguments()); |
4427 CHECK_BAILOUT; | 4449 CHECK_BAILOUT; |
4428 | 4450 |
4429 VISIT_FOR_VALUE(expr->expression()); | 4451 VISIT_FOR_VALUE(expr->expression()); |
4430 HValue* function = Pop(); | 4452 HValue* function = Pop(); |
4431 AddInstruction(new HCheckFunction(function, expr->target())); | 4453 AddInstruction(new HCheckFunction(function, expr->target())); |
4432 | 4454 |
4433 // Replace the global object with the global receiver. | 4455 // Replace the global object with the global receiver. |
4434 HGlobalReceiver* global_receiver = new HGlobalReceiver; | 4456 HGlobalReceiver* global_receiver = new HGlobalReceiver(global_object); |
4435 // Index of the receiver from the top of the expression stack. | 4457 // Index of the receiver from the top of the expression stack. |
4436 const int receiver_index = argument_count - 1; | 4458 const int receiver_index = argument_count - 1; |
4437 AddInstruction(global_receiver); | 4459 AddInstruction(global_receiver); |
4438 ASSERT(environment()->ExpressionStackAt(receiver_index)-> | 4460 ASSERT(environment()->ExpressionStackAt(receiver_index)-> |
4439 IsGlobalObject()); | 4461 IsGlobalObject()); |
4440 environment()->SetExpressionStackAt(receiver_index, global_receiver); | 4462 environment()->SetExpressionStackAt(receiver_index, global_receiver); |
4441 | 4463 |
4442 if (TryInline(expr)) { | 4464 if (TryInline(expr)) { |
4443 if (subgraph()->HasExit()) { | 4465 if (subgraph()->HasExit()) { |
4444 HValue* return_value = Pop(); | 4466 HValue* return_value = Pop(); |
4445 // If we inlined a function in a test context then we need to | 4467 // If we inlined a function in a test context then we need to |
4446 // emit a simulate here to shadow the ones at the end of the | 4468 // emit a simulate here to shadow the ones at the end of the |
4447 // predecessor blocks. Those environments contain the return | 4469 // predecessor blocks. Those environments contain the return |
4448 // value on top and do not correspond to any actual state of the | 4470 // value on top and do not correspond to any actual state of the |
4449 // unoptimized code. | 4471 // unoptimized code. |
4450 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | 4472 if (ast_context()->IsEffect()) AddSimulate(expr->id()); |
4451 ast_context()->ReturnValue(return_value); | 4473 ast_context()->ReturnValue(return_value); |
4452 } | 4474 } |
4453 return; | 4475 return; |
4454 } | 4476 } |
4455 // Check for bailout, as trying to inline might fail due to bailout | 4477 // Check for bailout, as trying to inline might fail due to bailout |
4456 // during hydrogen processing. | 4478 // during hydrogen processing. |
4457 CHECK_BAILOUT; | 4479 CHECK_BAILOUT; |
4458 | 4480 |
4459 call = new HCallKnownGlobal(expr->target(), argument_count); | 4481 call = new HCallKnownGlobal(expr->target(), argument_count); |
4460 } else { | 4482 } else { |
4461 PushAndAdd(new HGlobalObject); | 4483 HContext* context = new HContext; |
4484 AddInstruction(context); | |
4485 PushAndAdd(new HGlobalObject(context)); | |
4462 VisitArgumentList(expr->arguments()); | 4486 VisitArgumentList(expr->arguments()); |
4463 CHECK_BAILOUT; | 4487 CHECK_BAILOUT; |
4464 | 4488 |
4465 call = new HCallGlobal(var->name(), argument_count); | 4489 call = new HCallGlobal(var->name(), argument_count); |
4466 } | 4490 } |
4467 | 4491 |
4468 } else { | 4492 } else { |
4469 PushAndAdd(new HGlobalReceiver); | 4493 HContext* context = new HContext; |
4494 HGlobalObject* global_object = new HGlobalObject(context); | |
4495 AddInstruction(context); | |
4496 AddInstruction(global_object); | |
4497 PushAndAdd(new HGlobalReceiver(global_object)); | |
4470 VisitArgumentList(expr->arguments()); | 4498 VisitArgumentList(expr->arguments()); |
4471 CHECK_BAILOUT; | 4499 CHECK_BAILOUT; |
4472 | 4500 |
4473 call = new HCallFunction(argument_count); | 4501 call = new HCallFunction(argument_count); |
4474 } | 4502 } |
4475 } | 4503 } |
4476 | 4504 |
4477 call->set_position(expr->position()); | 4505 call->set_position(expr->position()); |
4478 ProcessCall(call); | 4506 ProcessCall(call); |
4479 ast_context()->ReturnInstruction(call, expr->id()); | 4507 ast_context()->ReturnInstruction(call, expr->id()); |
(...skipping 1416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5896 } | 5924 } |
5897 } | 5925 } |
5898 | 5926 |
5899 #ifdef DEBUG | 5927 #ifdef DEBUG |
5900 if (graph_ != NULL) graph_->Verify(); | 5928 if (graph_ != NULL) graph_->Verify(); |
5901 if (allocator_ != NULL) allocator_->Verify(); | 5929 if (allocator_ != NULL) allocator_->Verify(); |
5902 #endif | 5930 #endif |
5903 } | 5931 } |
5904 | 5932 |
5905 } } // namespace v8::internal | 5933 } } // namespace v8::internal |
OLD | NEW |