OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/ast-graph-builder.h" | 5 #include "src/compiler/ast-graph-builder.h" |
6 | 6 |
7 #include "src/compiler.h" | 7 #include "src/compiler.h" |
8 #include "src/compiler/ast-loop-assignment-analyzer.h" | 8 #include "src/compiler/ast-loop-assignment-analyzer.h" |
9 #include "src/compiler/control-builders.h" | 9 #include "src/compiler/control-builders.h" |
10 #include "src/compiler/linkage.h" | 10 #include "src/compiler/linkage.h" |
(...skipping 3044 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3055 return info()->language_mode(); | 3055 return info()->language_mode(); |
3056 } | 3056 } |
3057 | 3057 |
3058 | 3058 |
3059 VectorSlotPair AstGraphBuilder::CreateVectorSlotPair( | 3059 VectorSlotPair AstGraphBuilder::CreateVectorSlotPair( |
3060 FeedbackVectorSlot slot) const { | 3060 FeedbackVectorSlot slot) const { |
3061 return VectorSlotPair(handle(info()->shared_info()->feedback_vector()), slot); | 3061 return VectorSlotPair(handle(info()->shared_info()->feedback_vector()), slot); |
3062 } | 3062 } |
3063 | 3063 |
3064 | 3064 |
| 3065 namespace { |
| 3066 |
| 3067 // Limit of context chain length to which inline check is possible. |
| 3068 const int kMaxCheckDepth = 30; |
| 3069 |
| 3070 // Sentinel for {TryLoadDynamicVariable} disabling inline checks. |
| 3071 const uint32_t kFullCheckRequired = -1; |
| 3072 |
| 3073 } // namespace |
| 3074 |
| 3075 |
3065 uint32_t AstGraphBuilder::ComputeBitsetForDynamicGlobal(Variable* variable) { | 3076 uint32_t AstGraphBuilder::ComputeBitsetForDynamicGlobal(Variable* variable) { |
3066 DCHECK_EQ(DYNAMIC_GLOBAL, variable->mode()); | 3077 DCHECK_EQ(DYNAMIC_GLOBAL, variable->mode()); |
3067 bool found_eval_scope = false; | 3078 bool found_eval_scope = false; |
3068 uint32_t check_depths = 0; | 3079 uint32_t check_depths = 0; |
3069 for (Scope* s = current_scope(); s != nullptr; s = s->outer_scope()) { | 3080 for (Scope* s = current_scope(); s != nullptr; s = s->outer_scope()) { |
3070 if (s->num_heap_slots() <= 0) continue; | 3081 if (s->num_heap_slots() <= 0) continue; |
3071 // TODO(mstarzinger): If we have reached an eval scope, we check all | 3082 // TODO(mstarzinger): If we have reached an eval scope, we check all |
3072 // extensions from this point. Replicated from full-codegen, figure out | 3083 // extensions from this point. Replicated from full-codegen, figure out |
3073 // whether this is still needed. If not, drop {found_eval_scope} below. | 3084 // whether this is still needed. If not, drop {found_eval_scope} below. |
3074 if (s->is_eval_scope()) found_eval_scope = true; | 3085 if (s->is_eval_scope()) found_eval_scope = true; |
3075 if (!s->calls_sloppy_eval() && !found_eval_scope) continue; | 3086 if (!s->calls_sloppy_eval() && !found_eval_scope) continue; |
3076 int depth = current_scope()->ContextChainLength(s); | 3087 int depth = current_scope()->ContextChainLength(s); |
3077 if (depth > DynamicGlobalAccess::kMaxCheckDepth) { | 3088 if (depth > kMaxCheckDepth) return kFullCheckRequired; |
3078 return DynamicGlobalAccess::kFullCheckRequired; | |
3079 } | |
3080 check_depths |= 1 << depth; | 3089 check_depths |= 1 << depth; |
3081 } | 3090 } |
3082 return check_depths; | 3091 return check_depths; |
3083 } | 3092 } |
3084 | 3093 |
3085 | 3094 |
3086 uint32_t AstGraphBuilder::ComputeBitsetForDynamicContext(Variable* variable) { | 3095 uint32_t AstGraphBuilder::ComputeBitsetForDynamicContext(Variable* variable) { |
3087 DCHECK_EQ(DYNAMIC_LOCAL, variable->mode()); | 3096 DCHECK_EQ(DYNAMIC_LOCAL, variable->mode()); |
3088 uint32_t check_depths = 0; | 3097 uint32_t check_depths = 0; |
3089 for (Scope* s = current_scope(); s != nullptr; s = s->outer_scope()) { | 3098 for (Scope* s = current_scope(); s != nullptr; s = s->outer_scope()) { |
3090 if (s->num_heap_slots() <= 0) continue; | 3099 if (s->num_heap_slots() <= 0) continue; |
3091 if (!s->calls_sloppy_eval() && s != variable->scope()) continue; | 3100 if (!s->calls_sloppy_eval() && s != variable->scope()) continue; |
3092 int depth = current_scope()->ContextChainLength(s); | 3101 int depth = current_scope()->ContextChainLength(s); |
3093 if (depth > DynamicContextAccess::kMaxCheckDepth) { | 3102 if (depth > kMaxCheckDepth) return kFullCheckRequired; |
3094 return DynamicContextAccess::kFullCheckRequired; | |
3095 } | |
3096 check_depths |= 1 << depth; | 3103 check_depths |= 1 << depth; |
3097 if (s == variable->scope()) break; | 3104 if (s == variable->scope()) break; |
3098 } | 3105 } |
3099 return check_depths; | 3106 return check_depths; |
3100 } | 3107 } |
3101 | 3108 |
3102 | 3109 |
3103 Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) { | 3110 Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) { |
3104 DCHECK(environment()->stack_height() >= arity); | 3111 DCHECK(environment()->stack_height() >= arity); |
3105 Node** all = info()->zone()->NewArray<Node*>(arity); | 3112 Node** all = info()->zone()->NewArray<Node*>(arity); |
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3373 Node* undefined = jsgraph()->UndefinedConstant(); | 3380 Node* undefined = jsgraph()->UndefinedConstant(); |
3374 value = BuildHoleCheckSilent(value, undefined, value); | 3381 value = BuildHoleCheckSilent(value, undefined, value); |
3375 } else if (mode == LET || mode == CONST) { | 3382 } else if (mode == LET || mode == CONST) { |
3376 // Perform check for uninitialized let/const variables. | 3383 // Perform check for uninitialized let/const variables. |
3377 value = BuildHoleCheckThenThrow(value, variable, value, bailout_id); | 3384 value = BuildHoleCheckThenThrow(value, variable, value, bailout_id); |
3378 } | 3385 } |
3379 return value; | 3386 return value; |
3380 } | 3387 } |
3381 case VariableLocation::LOOKUP: { | 3388 case VariableLocation::LOOKUP: { |
3382 // Dynamic lookup of context variable (anywhere in the chain). | 3389 // Dynamic lookup of context variable (anywhere in the chain). |
3383 Node* value = jsgraph()->TheHoleConstant(); | |
3384 Handle<String> name = variable->name(); | 3390 Handle<String> name = variable->name(); |
3385 if (mode == DYNAMIC_GLOBAL) { | 3391 if (Node* node = |
3386 uint32_t check_bitset = ComputeBitsetForDynamicGlobal(variable); | 3392 TryLoadDynamicVariable(variable, name, bailout_id, states, |
3387 const Operator* op = javascript()->LoadDynamicGlobal( | 3393 feedback, combine, typeof_mode)) { |
3388 name, check_bitset, feedback, typeof_mode); | 3394 return node; |
3389 value = NewNode(op, BuildLoadFeedbackVector(), current_context()); | |
3390 states.AddToNode(value, bailout_id, combine); | |
3391 } else if (mode == DYNAMIC_LOCAL) { | |
3392 Variable* local = variable->local_if_not_shadowed(); | |
3393 DCHECK(local->location() == | |
3394 VariableLocation::CONTEXT); // Must be context. | |
3395 int depth = current_scope()->ContextChainLength(local->scope()); | |
3396 uint32_t check_bitset = ComputeBitsetForDynamicContext(variable); | |
3397 const Operator* op = javascript()->LoadDynamicContext( | |
3398 name, check_bitset, depth, local->index()); | |
3399 value = NewNode(op, current_context()); | |
3400 PrepareFrameState(value, bailout_id, combine); | |
3401 VariableMode local_mode = local->mode(); | |
3402 if (local_mode == CONST_LEGACY) { | |
3403 // Perform check for uninitialized legacy const variables. | |
3404 Node* undefined = jsgraph()->UndefinedConstant(); | |
3405 value = BuildHoleCheckSilent(value, undefined, value); | |
3406 } else if (local_mode == LET || local_mode == CONST) { | |
3407 // Perform check for uninitialized let/const variables. | |
3408 value = BuildHoleCheckThenThrow(value, local, value, bailout_id); | |
3409 } | |
3410 } else if (mode == DYNAMIC) { | |
3411 uint32_t check_bitset = DynamicGlobalAccess::kFullCheckRequired; | |
3412 const Operator* op = javascript()->LoadDynamicGlobal( | |
3413 name, check_bitset, feedback, typeof_mode); | |
3414 value = NewNode(op, BuildLoadFeedbackVector(), current_context()); | |
3415 states.AddToNode(value, bailout_id, combine); | |
3416 } | 3395 } |
| 3396 const Operator* op = javascript()->LoadDynamic(name, typeof_mode); |
| 3397 Node* value = NewNode(op, BuildLoadFeedbackVector(), current_context()); |
| 3398 states.AddToNode(value, bailout_id, combine); |
3417 return value; | 3399 return value; |
3418 } | 3400 } |
3419 } | 3401 } |
3420 UNREACHABLE(); | 3402 UNREACHABLE(); |
3421 return NULL; | 3403 return NULL; |
3422 } | 3404 } |
3423 | 3405 |
3424 | 3406 |
3425 Node* AstGraphBuilder::BuildVariableDelete(Variable* variable, | 3407 Node* AstGraphBuilder::BuildVariableDelete(Variable* variable, |
3426 BailoutId bailout_id, | 3408 BailoutId bailout_id, |
(...skipping 473 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3900 | 3882 |
3901 | 3883 |
3902 Node* AstGraphBuilder::TryLoadGlobalConstant(Handle<Name> name) { | 3884 Node* AstGraphBuilder::TryLoadGlobalConstant(Handle<Name> name) { |
3903 // Optimize global constants like "undefined", "Infinity", and "NaN". | 3885 // Optimize global constants like "undefined", "Infinity", and "NaN". |
3904 Handle<Object> constant_value = isolate()->factory()->GlobalConstantFor(name); | 3886 Handle<Object> constant_value = isolate()->factory()->GlobalConstantFor(name); |
3905 if (!constant_value.is_null()) return jsgraph()->Constant(constant_value); | 3887 if (!constant_value.is_null()) return jsgraph()->Constant(constant_value); |
3906 return nullptr; | 3888 return nullptr; |
3907 } | 3889 } |
3908 | 3890 |
3909 | 3891 |
| 3892 Node* AstGraphBuilder::TryLoadDynamicVariable( |
| 3893 Variable* variable, Handle<String> name, BailoutId bailout_id, |
| 3894 FrameStateBeforeAndAfter& states, const VectorSlotPair& feedback, |
| 3895 OutputFrameStateCombine combine, TypeofMode typeof_mode) { |
| 3896 VariableMode mode = variable->mode(); |
| 3897 |
| 3898 if (mode == DYNAMIC_GLOBAL) { |
| 3899 uint32_t bitset = ComputeBitsetForDynamicGlobal(variable); |
| 3900 if (bitset == kFullCheckRequired) return nullptr; |
| 3901 |
| 3902 // We are using two blocks to model fast and slow cases. |
| 3903 BlockBuilder fast_block(this); |
| 3904 BlockBuilder slow_block(this); |
| 3905 environment()->Push(jsgraph()->TheHoleConstant()); |
| 3906 slow_block.BeginBlock(); |
| 3907 environment()->Pop(); |
| 3908 fast_block.BeginBlock(); |
| 3909 |
| 3910 // Perform checks whether the fast mode applies, by looking for any |
| 3911 // extension object which might shadow the optimistic declaration. |
| 3912 for (int depth = 0; bitset != 0; bitset >>= 1, depth++) { |
| 3913 if ((bitset & 1) == 0) continue; |
| 3914 Node* load = NewNode( |
| 3915 javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false), |
| 3916 current_context()); |
| 3917 Node* check = |
| 3918 NewNode(javascript()->CallRuntime(Runtime::kInlineIsSmi, 1), load); |
| 3919 fast_block.BreakUnless(check, BranchHint::kTrue); |
| 3920 } |
| 3921 |
| 3922 // Fast case, because variable is not shadowed. Perform global slot load. |
| 3923 Node* fast = BuildGlobalLoad(name, feedback, typeof_mode); |
| 3924 states.AddToNode(fast, bailout_id, combine); |
| 3925 environment()->Push(fast); |
| 3926 slow_block.Break(); |
| 3927 environment()->Pop(); |
| 3928 fast_block.EndBlock(); |
| 3929 |
| 3930 // Slow case, because variable potentially shadowed. Perform dynamic lookup. |
| 3931 const Operator* op = javascript()->LoadDynamic(name, typeof_mode); |
| 3932 Node* slow = NewNode(op, BuildLoadFeedbackVector(), current_context()); |
| 3933 states.AddToNode(slow, bailout_id, combine); |
| 3934 environment()->Push(slow); |
| 3935 slow_block.EndBlock(); |
| 3936 |
| 3937 return environment()->Pop(); |
| 3938 } |
| 3939 |
| 3940 if (mode == DYNAMIC_LOCAL) { |
| 3941 uint32_t bitset = ComputeBitsetForDynamicContext(variable); |
| 3942 if (bitset == kFullCheckRequired) return nullptr; |
| 3943 |
| 3944 // We are using two blocks to model fast and slow cases. |
| 3945 BlockBuilder fast_block(this); |
| 3946 BlockBuilder slow_block(this); |
| 3947 environment()->Push(jsgraph()->TheHoleConstant()); |
| 3948 slow_block.BeginBlock(); |
| 3949 environment()->Pop(); |
| 3950 fast_block.BeginBlock(); |
| 3951 |
| 3952 // Perform checks whether the fast mode applies, by looking for any |
| 3953 // extension object which might shadow the optimistic declaration. |
| 3954 for (int depth = 0; bitset != 0; bitset >>= 1, depth++) { |
| 3955 if ((bitset & 1) == 0) continue; |
| 3956 Node* load = NewNode( |
| 3957 javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false), |
| 3958 current_context()); |
| 3959 Node* check = |
| 3960 NewNode(javascript()->CallRuntime(Runtime::kInlineIsSmi, 1), load); |
| 3961 fast_block.BreakUnless(check, BranchHint::kTrue); |
| 3962 } |
| 3963 |
| 3964 // Fast case, because variable is not shadowed. Perform context slot load. |
| 3965 Variable* local = variable->local_if_not_shadowed(); |
| 3966 DCHECK(local->location() == VariableLocation::CONTEXT); // Must be context. |
| 3967 Node* fast = BuildVariableLoad(local, bailout_id, states, feedback, combine, |
| 3968 typeof_mode); |
| 3969 environment()->Push(fast); |
| 3970 slow_block.Break(); |
| 3971 environment()->Pop(); |
| 3972 fast_block.EndBlock(); |
| 3973 |
| 3974 // Slow case, because variable potentially shadowed. Perform dynamic lookup. |
| 3975 const Operator* op = javascript()->LoadDynamic(name, typeof_mode); |
| 3976 Node* slow = NewNode(op, BuildLoadFeedbackVector(), current_context()); |
| 3977 states.AddToNode(slow, bailout_id, combine); |
| 3978 environment()->Push(slow); |
| 3979 slow_block.EndBlock(); |
| 3980 |
| 3981 return environment()->Pop(); |
| 3982 } |
| 3983 |
| 3984 return nullptr; |
| 3985 } |
| 3986 |
| 3987 |
3910 Node* AstGraphBuilder::TryFastToBoolean(Node* input) { | 3988 Node* AstGraphBuilder::TryFastToBoolean(Node* input) { |
3911 switch (input->opcode()) { | 3989 switch (input->opcode()) { |
3912 case IrOpcode::kNumberConstant: { | 3990 case IrOpcode::kNumberConstant: { |
3913 NumberMatcher m(input); | 3991 NumberMatcher m(input); |
3914 return jsgraph_->BooleanConstant(!m.Is(0) && !m.IsNaN()); | 3992 return jsgraph_->BooleanConstant(!m.Is(0) && !m.IsNaN()); |
3915 } | 3993 } |
3916 case IrOpcode::kHeapConstant: { | 3994 case IrOpcode::kHeapConstant: { |
3917 Handle<HeapObject> object = HeapObjectMatcher(input).Value(); | 3995 Handle<HeapObject> object = HeapObjectMatcher(input).Value(); |
3918 return jsgraph_->BooleanConstant(object->BooleanValue()); | 3996 return jsgraph_->BooleanConstant(object->BooleanValue()); |
3919 } | 3997 } |
(...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4282 // Phi does not exist yet, introduce one. | 4360 // Phi does not exist yet, introduce one. |
4283 value = NewPhi(inputs, value, control); | 4361 value = NewPhi(inputs, value, control); |
4284 value->ReplaceInput(inputs - 1, other); | 4362 value->ReplaceInput(inputs - 1, other); |
4285 } | 4363 } |
4286 return value; | 4364 return value; |
4287 } | 4365 } |
4288 | 4366 |
4289 } // namespace compiler | 4367 } // namespace compiler |
4290 } // namespace internal | 4368 } // namespace internal |
4291 } // namespace v8 | 4369 } // namespace v8 |
OLD | NEW |