OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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/code-stub-assembler.h" | 5 #include "src/compiler/code-stub-assembler.h" |
6 | 6 |
7 #include <ostream> | 7 #include <ostream> |
8 | 8 |
9 #include "src/code-factory.h" | 9 #include "src/code-factory.h" |
10 #include "src/compiler/graph.h" | 10 #include "src/compiler/graph.h" |
11 #include "src/compiler/instruction-selector.h" | 11 #include "src/compiler/instruction-selector.h" |
12 #include "src/compiler/linkage.h" | 12 #include "src/compiler/linkage.h" |
13 #include "src/compiler/pipeline.h" | 13 #include "src/compiler/pipeline.h" |
14 #include "src/compiler/raw-machine-assembler.h" | 14 #include "src/compiler/raw-machine-assembler.h" |
15 #include "src/compiler/schedule.h" | 15 #include "src/compiler/schedule.h" |
16 #include "src/frames.h" | 16 #include "src/frames.h" |
17 #include "src/interface-descriptors.h" | 17 #include "src/interface-descriptors.h" |
18 #include "src/interpreter/bytecodes.h" | 18 #include "src/interpreter/bytecodes.h" |
19 #include "src/machine-type.h" | 19 #include "src/machine-type.h" |
20 #include "src/macro-assembler.h" | 20 #include "src/macro-assembler.h" |
21 #include "src/zone.h" | 21 #include "src/zone.h" |
22 | 22 |
23 namespace v8 { | 23 namespace v8 { |
24 namespace internal { | 24 namespace internal { |
25 namespace compiler { | 25 namespace compiler { |
26 | 26 |
27 | |
28 CodeStubAssembler::CodeStubAssembler(Isolate* isolate, Zone* zone, | 27 CodeStubAssembler::CodeStubAssembler(Isolate* isolate, Zone* zone, |
29 const CallInterfaceDescriptor& descriptor, | 28 const CallInterfaceDescriptor& descriptor, |
30 Code::Flags flags, const char* name) | 29 Code::Flags flags, const char* name) |
31 : raw_assembler_(new RawMachineAssembler( | 30 : raw_assembler_(new RawMachineAssembler( |
32 isolate, new (zone) Graph(zone), | 31 isolate, new (zone) Graph(zone), |
33 Linkage::GetStubCallDescriptor(isolate, zone, descriptor, 0, | 32 Linkage::GetStubCallDescriptor(isolate, zone, descriptor, 0, |
34 CallDescriptor::kNoFlags))), | 33 CallDescriptor::kNoFlags))), |
35 flags_(flags), | 34 flags_(flags), |
36 name_(name), | 35 name_(name), |
37 code_generated_(false) {} | 36 code_generated_(false), |
38 | 37 variables_(zone) {} |
39 | 38 |
40 CodeStubAssembler::~CodeStubAssembler() {} | 39 CodeStubAssembler::~CodeStubAssembler() {} |
41 | 40 |
42 | 41 |
43 Handle<Code> CodeStubAssembler::GenerateCode() { | 42 Handle<Code> CodeStubAssembler::GenerateCode() { |
44 DCHECK(!code_generated_); | 43 DCHECK(!code_generated_); |
45 | 44 |
46 Schedule* schedule = raw_assembler_->Export(); | 45 Schedule* schedule = raw_assembler_->Export(); |
47 Handle<Code> code = Pipeline::GenerateCodeForCodeStub( | 46 Handle<Code> code = Pipeline::GenerateCodeForCodeStub( |
48 isolate(), raw_assembler_->call_descriptor(), graph(), schedule, flags_, | 47 isolate(), raw_assembler_->call_descriptor(), graph(), schedule, flags_, |
(...skipping 21 matching lines...) Expand all Loading... |
70 | 69 |
71 Node* CodeStubAssembler::HeapConstant(Handle<HeapObject> object) { | 70 Node* CodeStubAssembler::HeapConstant(Handle<HeapObject> object) { |
72 return raw_assembler_->HeapConstant(object); | 71 return raw_assembler_->HeapConstant(object); |
73 } | 72 } |
74 | 73 |
75 | 74 |
76 Node* CodeStubAssembler::BooleanConstant(bool value) { | 75 Node* CodeStubAssembler::BooleanConstant(bool value) { |
77 return raw_assembler_->BooleanConstant(value); | 76 return raw_assembler_->BooleanConstant(value); |
78 } | 77 } |
79 | 78 |
| 79 Node* CodeStubAssembler::ExternalConstant(ExternalReference address) { |
| 80 return raw_assembler_->ExternalConstant(address); |
| 81 } |
80 | 82 |
81 Node* CodeStubAssembler::Parameter(int value) { | 83 Node* CodeStubAssembler::Parameter(int value) { |
82 return raw_assembler_->Parameter(value); | 84 return raw_assembler_->Parameter(value); |
83 } | 85 } |
84 | 86 |
85 | 87 |
86 void CodeStubAssembler::Return(Node* value) { | 88 void CodeStubAssembler::Return(Node* value) { |
87 return raw_assembler_->Return(value); | 89 return raw_assembler_->Return(value); |
88 } | 90 } |
89 | 91 |
| 92 void CodeStubAssembler::Bind(CodeStubAssembler::Label* label) { |
| 93 return label->Bind(); |
| 94 } |
| 95 |
| 96 Node* CodeStubAssembler::LoadFramePointer() { |
| 97 return raw_assembler_->LoadFramePointer(); |
| 98 } |
90 | 99 |
91 Node* CodeStubAssembler::SmiShiftBitsConstant() { | 100 Node* CodeStubAssembler::SmiShiftBitsConstant() { |
92 return Int32Constant(kSmiShiftSize + kSmiTagSize); | 101 return Int32Constant(kSmiShiftSize + kSmiTagSize); |
93 } | 102 } |
94 | 103 |
95 | 104 |
96 Node* CodeStubAssembler::SmiTag(Node* value) { | 105 Node* CodeStubAssembler::SmiTag(Node* value) { |
97 return raw_assembler_->WordShl(value, SmiShiftBitsConstant()); | 106 return raw_assembler_->WordShl(value, SmiShiftBitsConstant()); |
98 } | 107 } |
99 | 108 |
100 | 109 |
101 Node* CodeStubAssembler::SmiUntag(Node* value) { | 110 Node* CodeStubAssembler::SmiUntag(Node* value) { |
102 return raw_assembler_->WordSar(value, SmiShiftBitsConstant()); | 111 return raw_assembler_->WordSar(value, SmiShiftBitsConstant()); |
103 } | 112 } |
104 | 113 |
105 | 114 #define DEFINE_CODE_STUB_ASSEMBER_BINARY_OP(name) \ |
106 Node* CodeStubAssembler::IntPtrAdd(Node* a, Node* b) { | 115 Node* CodeStubAssembler::name(Node* a, Node* b) { \ |
107 return raw_assembler_->IntPtrAdd(a, b); | 116 return raw_assembler_->name(a, b); \ |
108 } | 117 } |
109 | 118 CODE_STUB_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_STUB_ASSEMBER_BINARY_OP) |
110 | 119 #undef DEFINE_CODE_STUB_ASSEMBER_BINARY_OP |
111 Node* CodeStubAssembler::IntPtrSub(Node* a, Node* b) { | |
112 return raw_assembler_->IntPtrSub(a, b); | |
113 } | |
114 | |
115 | 120 |
116 Node* CodeStubAssembler::WordShl(Node* value, int shift) { | 121 Node* CodeStubAssembler::WordShl(Node* value, int shift) { |
117 return raw_assembler_->WordShl(value, Int32Constant(shift)); | 122 return raw_assembler_->WordShl(value, Int32Constant(shift)); |
118 } | 123 } |
119 | 124 |
| 125 Node* CodeStubAssembler::WordIsSmi(Node* a) { |
| 126 return WordEqual(raw_assembler_->WordAnd(a, Int32Constant(kSmiTagMask)), |
| 127 Int32Constant(0)); |
| 128 } |
| 129 |
| 130 Node* CodeStubAssembler::LoadBufferObject(Node* buffer, int offset) { |
| 131 return raw_assembler_->Load(MachineType::AnyTagged(), buffer, |
| 132 IntPtrConstant(offset)); |
| 133 } |
120 | 134 |
121 Node* CodeStubAssembler::LoadObjectField(Node* object, int offset) { | 135 Node* CodeStubAssembler::LoadObjectField(Node* object, int offset) { |
122 return raw_assembler_->Load(MachineType::AnyTagged(), object, | 136 return raw_assembler_->Load(MachineType::AnyTagged(), object, |
123 IntPtrConstant(offset - kHeapObjectTag)); | 137 IntPtrConstant(offset - kHeapObjectTag)); |
124 } | 138 } |
125 | 139 |
| 140 Node* CodeStubAssembler::LoadFixedArrayElementSmiIndex(Node* object, |
| 141 Node* smi_index, |
| 142 int additional_offset) { |
| 143 Node* header_size = raw_assembler_->Int32Constant( |
| 144 additional_offset + FixedArray::kHeaderSize - kHeapObjectTag); |
| 145 Node* scaled_index = |
| 146 (kSmiShiftSize == 0) |
| 147 ? raw_assembler_->Word32Shl( |
| 148 smi_index, Int32Constant(kPointerSizeLog2 - kSmiTagSize)) |
| 149 : raw_assembler_->Word32Shl(SmiUntag(smi_index), |
| 150 Int32Constant(kPointerSizeLog2)); |
| 151 Node* offset = raw_assembler_->Int32Add(scaled_index, header_size); |
| 152 return raw_assembler_->Load(MachineType::AnyTagged(), object, offset); |
| 153 } |
| 154 |
| 155 Node* CodeStubAssembler::LoadFixedArrayElementConstantIndex(Node* object, |
| 156 int index) { |
| 157 Node* offset = raw_assembler_->Int32Constant( |
| 158 FixedArray::kHeaderSize - kHeapObjectTag + index * kPointerSize); |
| 159 return raw_assembler_->Load(MachineType::AnyTagged(), object, offset); |
| 160 } |
| 161 |
| 162 Node* CodeStubAssembler::LoadRoot(Heap::RootListIndex root_index) { |
| 163 if (isolate()->heap()->RootCanBeTreatedAsConstant(root_index)) { |
| 164 Handle<Object> root = isolate()->heap()->root_handle(root_index); |
| 165 if (root->IsSmi()) { |
| 166 return Int32Constant(Handle<Smi>::cast(root)->value()); |
| 167 } else { |
| 168 return HeapConstant(Handle<HeapObject>::cast(root)); |
| 169 } |
| 170 } |
| 171 |
| 172 compiler::Node* roots_array_start = |
| 173 ExternalConstant(ExternalReference::roots_array_start(isolate())); |
| 174 USE(roots_array_start); |
| 175 |
| 176 // TODO(danno): Implement thee root-access case where the root is not constant |
| 177 // and must be loaded from the root array. |
| 178 UNIMPLEMENTED(); |
| 179 return nullptr; |
| 180 } |
126 | 181 |
127 Node* CodeStubAssembler::CallN(CallDescriptor* descriptor, Node* code_target, | 182 Node* CodeStubAssembler::CallN(CallDescriptor* descriptor, Node* code_target, |
128 Node** args) { | 183 Node** args) { |
129 return raw_assembler_->CallN(descriptor, code_target, args); | 184 return raw_assembler_->CallN(descriptor, code_target, args); |
130 } | 185 } |
131 | 186 |
132 | 187 |
133 Node* CodeStubAssembler::TailCallN(CallDescriptor* descriptor, | 188 Node* CodeStubAssembler::TailCallN(CallDescriptor* descriptor, |
134 Node* code_target, Node** args) { | 189 Node* code_target, Node** args) { |
135 return raw_assembler_->TailCallN(descriptor, code_target, args); | 190 return raw_assembler_->TailCallN(descriptor, code_target, args); |
136 } | 191 } |
137 | 192 |
138 | 193 |
139 Node* CodeStubAssembler::CallRuntime(Runtime::FunctionId function_id, | 194 Node* CodeStubAssembler::CallRuntime(Runtime::FunctionId function_id, |
140 Node* context, Node* arg1) { | 195 Node* context, Node* arg1) { |
141 return raw_assembler_->CallRuntime1(function_id, arg1, context); | 196 return raw_assembler_->CallRuntime1(function_id, arg1, context); |
142 } | 197 } |
143 | 198 |
144 | 199 |
145 Node* CodeStubAssembler::CallRuntime(Runtime::FunctionId function_id, | 200 Node* CodeStubAssembler::CallRuntime(Runtime::FunctionId function_id, |
146 Node* context, Node* arg1, Node* arg2) { | 201 Node* context, Node* arg1, Node* arg2) { |
147 return raw_assembler_->CallRuntime2(function_id, arg1, arg2, context); | 202 return raw_assembler_->CallRuntime2(function_id, arg1, arg2, context); |
148 } | 203 } |
149 | 204 |
150 | |
151 Node* CodeStubAssembler::TailCallRuntime(Runtime::FunctionId function_id, | 205 Node* CodeStubAssembler::TailCallRuntime(Runtime::FunctionId function_id, |
152 Node* context, Node* arg1) { | 206 Node* context, Node* arg1) { |
153 return raw_assembler_->TailCallRuntime1(function_id, arg1, context); | 207 return raw_assembler_->TailCallRuntime1(function_id, arg1, context); |
154 } | 208 } |
155 | 209 |
156 | |
157 Node* CodeStubAssembler::TailCallRuntime(Runtime::FunctionId function_id, | 210 Node* CodeStubAssembler::TailCallRuntime(Runtime::FunctionId function_id, |
158 Node* context, Node* arg1, | 211 Node* context, Node* arg1, |
159 Node* arg2) { | 212 Node* arg2) { |
160 return raw_assembler_->TailCallRuntime2(function_id, arg1, arg2, context); | 213 return raw_assembler_->TailCallRuntime2(function_id, arg1, arg2, context); |
161 } | 214 } |
162 | 215 |
| 216 Node* CodeStubAssembler::TailCallRuntime(Runtime::FunctionId function_id, |
| 217 Node* context, Node* arg1, Node* arg2, |
| 218 Node* arg3) { |
| 219 return raw_assembler_->TailCallRuntime3(function_id, arg1, arg2, arg3, |
| 220 context); |
| 221 } |
| 222 |
| 223 Node* CodeStubAssembler::TailCallRuntime(Runtime::FunctionId function_id, |
| 224 Node* context, Node* arg1, Node* arg2, |
| 225 Node* arg3, Node* arg4) { |
| 226 return raw_assembler_->TailCallRuntime4(function_id, arg1, arg2, arg3, arg4, |
| 227 context); |
| 228 } |
| 229 |
| 230 Node* CodeStubAssembler::TailCallStub(CodeStub& stub, Node** args) { |
| 231 Node* code_target = HeapConstant(stub.GetCode()); |
| 232 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor( |
| 233 isolate(), zone(), stub.GetCallInterfaceDescriptor(), |
| 234 stub.GetStackParameterCount(), CallDescriptor::kSupportsTailCalls); |
| 235 return raw_assembler_->TailCallN(descriptor, code_target, args); |
| 236 } |
| 237 |
| 238 Node* CodeStubAssembler::TailCall( |
| 239 const CallInterfaceDescriptor& interface_descriptor, Node* code_target, |
| 240 Node** args) { |
| 241 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor( |
| 242 isolate(), zone(), interface_descriptor, |
| 243 interface_descriptor.GetStackParameterCount(), |
| 244 CallDescriptor::kSupportsTailCalls); |
| 245 return raw_assembler_->TailCallN(descriptor, code_target, args); |
| 246 } |
| 247 |
| 248 void CodeStubAssembler::Goto(CodeStubAssembler::Label* label) { |
| 249 label->MergeVariables(); |
| 250 raw_assembler_->Goto(label->label_); |
| 251 } |
| 252 |
| 253 void CodeStubAssembler::Branch(Node* condition, |
| 254 CodeStubAssembler::Label* true_label, |
| 255 CodeStubAssembler::Label* false_label) { |
| 256 true_label->MergeVariables(); |
| 257 false_label->MergeVariables(); |
| 258 return raw_assembler_->Branch(condition, true_label->label_, |
| 259 false_label->label_); |
| 260 } |
| 261 |
| 262 void CodeStubAssembler::Switch(Node* index, Label* default_label, |
| 263 int32_t* case_values, Label** case_labels, |
| 264 size_t case_count) { |
| 265 RawMachineLabel** labels = |
| 266 new (zone()->New(sizeof(RawMachineLabel*) * case_count)) |
| 267 RawMachineLabel*[case_count]; |
| 268 for (size_t i = 0; i < case_count; ++i) { |
| 269 labels[i] = case_labels[i]->label_; |
| 270 case_labels[i]->MergeVariables(); |
| 271 default_label->MergeVariables(); |
| 272 } |
| 273 return raw_assembler_->Switch(index, default_label->label_, case_values, |
| 274 labels, case_count); |
| 275 } |
163 | 276 |
164 // RawMachineAssembler delegate helpers: | 277 // RawMachineAssembler delegate helpers: |
165 Isolate* CodeStubAssembler::isolate() { return raw_assembler_->isolate(); } | 278 Isolate* CodeStubAssembler::isolate() { return raw_assembler_->isolate(); } |
166 | 279 |
167 | 280 |
168 Graph* CodeStubAssembler::graph() { return raw_assembler_->graph(); } | 281 Graph* CodeStubAssembler::graph() { return raw_assembler_->graph(); } |
169 | 282 |
170 | 283 |
171 Zone* CodeStubAssembler::zone() { return raw_assembler_->zone(); } | 284 Zone* CodeStubAssembler::zone() { return raw_assembler_->zone(); } |
172 | 285 |
| 286 // The core implementation of Variable is stored through an indirection so |
| 287 // that it can outlive the often block-scoped Variable declarations. This is |
| 288 // needed to ensure that variable binding and merging through phis can |
| 289 // properly be verified. |
| 290 class CodeStubAssembler::Variable::Impl : public ZoneObject { |
| 291 public: |
| 292 explicit Impl(MachineRepresentation rep) : value_(nullptr), rep_(rep) {} |
| 293 Node* value_; |
| 294 MachineRepresentation rep_; |
| 295 }; |
| 296 |
| 297 CodeStubAssembler::Variable::Variable(CodeStubAssembler* assembler, |
| 298 MachineRepresentation rep) |
| 299 : impl_(new (assembler->zone()) Impl(rep)) { |
| 300 assembler->variables_.push_back(impl_); |
| 301 } |
| 302 |
| 303 void CodeStubAssembler::Variable::Bind(Node* value) { impl_->value_ = value; } |
| 304 |
| 305 Node* CodeStubAssembler::Variable::value() const { |
| 306 DCHECK_NOT_NULL(impl_->value_); |
| 307 return impl_->value_; |
| 308 } |
| 309 |
| 310 MachineRepresentation CodeStubAssembler::Variable::rep() const { |
| 311 return impl_->rep_; |
| 312 } |
| 313 |
| 314 bool CodeStubAssembler::Variable::IsBound() const { |
| 315 return impl_->value_ != nullptr; |
| 316 } |
| 317 |
| 318 CodeStubAssembler::Label::Label(CodeStubAssembler* assembler) |
| 319 : bound_(false), merge_count_(0), assembler_(assembler), label_(nullptr) { |
| 320 void* buffer = assembler->zone()->New(sizeof(RawMachineLabel)); |
| 321 label_ = new (buffer) RawMachineLabel(); |
| 322 } |
| 323 |
| 324 CodeStubAssembler::Label::Label(CodeStubAssembler* assembler, |
| 325 int merged_value_count, |
| 326 CodeStubAssembler::Variable** merged_variables) |
| 327 : bound_(false), merge_count_(0), assembler_(assembler), label_(nullptr) { |
| 328 void* buffer = assembler->zone()->New(sizeof(RawMachineLabel)); |
| 329 label_ = new (buffer) RawMachineLabel(); |
| 330 for (int i = 0; i < merged_value_count; ++i) { |
| 331 variable_phis_[merged_variables[i]->impl_] = nullptr; |
| 332 } |
| 333 } |
| 334 |
| 335 CodeStubAssembler::Label::Label(CodeStubAssembler* assembler, |
| 336 CodeStubAssembler::Variable* merged_variable) |
| 337 : CodeStubAssembler::Label(assembler, 1, &merged_variable) {} |
| 338 |
| 339 void CodeStubAssembler::Label::MergeVariables() { |
| 340 ++merge_count_; |
| 341 for (auto var : assembler_->variables_) { |
| 342 size_t count = 0; |
| 343 Node* node = var->value_; |
| 344 if (node != nullptr) { |
| 345 auto i = variable_merges_.find(var); |
| 346 if (i != variable_merges_.end()) { |
| 347 i->second.push_back(node); |
| 348 count = i->second.size(); |
| 349 } else { |
| 350 count = 1; |
| 351 variable_merges_[var] = std::vector<Node*>(1, node); |
| 352 } |
| 353 } |
| 354 // If the following asserts, then you've jumped to a label without a bound |
| 355 // variable along that path that expects to merge its value into a phi. |
| 356 DCHECK(variable_phis_.find(var) == variable_phis_.end() || |
| 357 count == merge_count_); |
| 358 USE(count); |
| 359 |
| 360 // If the label is already bound, we already know the set of variables to |
| 361 // merge and phi nodes have already been created. |
| 362 if (bound_) { |
| 363 auto phi = variable_phis_.find(var); |
| 364 if (phi != variable_phis_.end()) { |
| 365 DCHECK_NOT_NULL(phi->second); |
| 366 assembler_->raw_assembler_->AppendPhiInput(phi->second, node); |
| 367 } else { |
| 368 auto i = variable_merges_.find(var); |
| 369 USE(i); |
| 370 // If the following assert fires, then you've declared a variable that |
| 371 // has the same bound value along all paths up until the point you bound |
| 372 // this label, but then later merged a path with a new value for the |
| 373 // variable after the label bind (it's not possible to add phis to the |
| 374 // bound label after the fact, just make sure to list the variable in |
| 375 // the label's constructor's list of merged variables). |
| 376 DCHECK(find_if(i->second.begin(), i->second.end(), |
| 377 [node](Node* e) -> bool { return node != e; }) == |
| 378 i->second.end()); |
| 379 } |
| 380 } |
| 381 } |
| 382 } |
| 383 |
| 384 void CodeStubAssembler::Label::Bind() { |
| 385 DCHECK(!bound_); |
| 386 assembler_->raw_assembler_->Bind(label_); |
| 387 |
| 388 // Make sure that all variables that have changed along any path up to this |
| 389 // point are marked as merge variables. |
| 390 for (auto var : assembler_->variables_) { |
| 391 Node* shared_value = nullptr; |
| 392 auto i = variable_merges_.find(var); |
| 393 if (i != variable_merges_.end()) { |
| 394 for (auto value : i->second) { |
| 395 DCHECK(value != nullptr); |
| 396 if (value != shared_value) { |
| 397 if (shared_value == nullptr) { |
| 398 shared_value = value; |
| 399 } else { |
| 400 variable_phis_[var] = nullptr; |
| 401 } |
| 402 } |
| 403 } |
| 404 } |
| 405 } |
| 406 |
| 407 for (auto var : variable_phis_) { |
| 408 CodeStubAssembler::Variable::Impl* var_impl = var.first; |
| 409 auto i = variable_merges_.find(var_impl); |
| 410 // If the following assert fires, then a variable that has been marked as |
| 411 // being merged at the label--either by explicitly marking it so in the |
| 412 // label constructor or by having seen different bound values at branches |
| 413 // into the label--doesn't have a bound value along all of the paths that |
| 414 // have been merged into the label up to this point. |
| 415 DCHECK(i != variable_merges_.end() && i->second.size() == merge_count_); |
| 416 Node* phi = assembler_->raw_assembler_->Phi( |
| 417 var.first->rep_, static_cast<int>(merge_count_), &(i->second[0])); |
| 418 variable_phis_[var_impl] = phi; |
| 419 } |
| 420 |
| 421 // Bind all variables to a merge phi, the common value along all paths or |
| 422 // null. |
| 423 for (auto var : assembler_->variables_) { |
| 424 auto i = variable_phis_.find(var); |
| 425 if (i != variable_phis_.end()) { |
| 426 var->value_ = i->second; |
| 427 } else { |
| 428 auto j = variable_merges_.find(var); |
| 429 if (j != variable_merges_.end() && j->second.size() == merge_count_) { |
| 430 var->value_ = j->second.back(); |
| 431 } else { |
| 432 var->value_ = nullptr; |
| 433 } |
| 434 } |
| 435 } |
| 436 |
| 437 bound_ = true; |
| 438 } |
173 | 439 |
174 } // namespace compiler | 440 } // namespace compiler |
175 } // namespace internal | 441 } // namespace internal |
176 } // namespace v8 | 442 } // namespace v8 |
OLD | NEW |