| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 7 | 7 |
| 8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
| 9 | 9 |
| 10 #include "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 intptr_t slot_ix = 0; | 93 intptr_t slot_ix = 0; |
| 94 Environment* current = deopt_env_; | 94 Environment* current = deopt_env_; |
| 95 | 95 |
| 96 // Emit all kMaterializeObject instructions describing objects to be | 96 // Emit all kMaterializeObject instructions describing objects to be |
| 97 // materialized on the deoptimization as a prefix to the deoptimization info. | 97 // materialized on the deoptimization as a prefix to the deoptimization info. |
| 98 EmitMaterializations(deopt_env_, builder); | 98 EmitMaterializations(deopt_env_, builder); |
| 99 | 99 |
| 100 // The real frame starts here. | 100 // The real frame starts here. |
| 101 builder->MarkFrameStart(); | 101 builder->MarkFrameStart(); |
| 102 | 102 |
| 103 Zone* zone = compiler->zone(); |
| 104 |
| 103 // Callee's PC marker is not used anymore. Pass Code::null() to set to 0. | 105 // Callee's PC marker is not used anymore. Pass Code::null() to set to 0. |
| 104 builder->AddPcMarker(Function::Handle(), slot_ix++); | 106 builder->AddPcMarker(Function::Handle(zone), slot_ix++); |
| 105 | 107 |
| 106 // Current FP and PC. | 108 // Current FP and PC. |
| 107 builder->AddCallerFp(slot_ix++); | 109 builder->AddCallerFp(slot_ix++); |
| 108 builder->AddReturnAddress(Function::Handle(current->code().function()), | 110 builder->AddReturnAddress(Function::Handle(zone, current->code().function()), |
| 109 deopt_id(), | 111 deopt_id(), |
| 110 slot_ix++); | 112 slot_ix++); |
| 111 | 113 |
| 112 // Emit all values that are needed for materialization as a part of the | 114 // Emit all values that are needed for materialization as a part of the |
| 113 // expression stack for the bottom-most frame. This guarantees that GC | 115 // expression stack for the bottom-most frame. This guarantees that GC |
| 114 // will be able to find them during materialization. | 116 // will be able to find them during materialization. |
| 115 slot_ix = builder->EmitMaterializationArguments(slot_ix); | 117 slot_ix = builder->EmitMaterializationArguments(slot_ix); |
| 116 | 118 |
| 117 // For the innermost environment, set outgoing arguments and the locals. | 119 // For the innermost environment, set outgoing arguments and the locals. |
| 118 for (intptr_t i = current->Length() - 1; | 120 for (intptr_t i = current->Length() - 1; |
| 119 i >= current->fixed_parameter_count(); | 121 i >= current->fixed_parameter_count(); |
| 120 i--) { | 122 i--) { |
| 121 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); | 123 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); |
| 122 } | 124 } |
| 123 | 125 |
| 124 // Current PC marker and caller FP. | 126 // Current PC marker and caller FP. |
| 125 builder->AddPcMarker(Function::Handle(current->code().function()), slot_ix++); | 127 builder->AddPcMarker(Function::Handle( |
| 128 zone, current->code().function()), slot_ix++); |
| 126 builder->AddCallerFp(slot_ix++); | 129 builder->AddCallerFp(slot_ix++); |
| 127 | 130 |
| 128 Environment* previous = current; | 131 Environment* previous = current; |
| 129 current = current->outer(); | 132 current = current->outer(); |
| 130 while (current != NULL) { | 133 while (current != NULL) { |
| 131 // For any outer environment the deopt id is that of the call instruction | 134 // For any outer environment the deopt id is that of the call instruction |
| 132 // which is recorded in the outer environment. | 135 // which is recorded in the outer environment. |
| 133 builder->AddReturnAddress(Function::Handle(current->code().function()), | 136 builder->AddReturnAddress( |
| 134 Isolate::ToDeoptAfter(current->deopt_id()), | 137 Function::Handle(zone, current->code().function()), |
| 135 slot_ix++); | 138 Isolate::ToDeoptAfter(current->deopt_id()), |
| 139 slot_ix++); |
| 136 | 140 |
| 137 // The values of outgoing arguments can be changed from the inlined call so | 141 // The values of outgoing arguments can be changed from the inlined call so |
| 138 // we must read them from the previous environment. | 142 // we must read them from the previous environment. |
| 139 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 143 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
| 140 builder->AddCopy(previous->ValueAt(i), | 144 builder->AddCopy(previous->ValueAt(i), |
| 141 previous->LocationAt(i), | 145 previous->LocationAt(i), |
| 142 slot_ix++); | 146 slot_ix++); |
| 143 } | 147 } |
| 144 | 148 |
| 145 // Set the locals, note that outgoing arguments are not in the environment. | 149 // Set the locals, note that outgoing arguments are not in the environment. |
| 146 for (intptr_t i = current->Length() - 1; | 150 for (intptr_t i = current->Length() - 1; |
| 147 i >= current->fixed_parameter_count(); | 151 i >= current->fixed_parameter_count(); |
| 148 i--) { | 152 i--) { |
| 149 builder->AddCopy(current->ValueAt(i), | 153 builder->AddCopy(current->ValueAt(i), |
| 150 current->LocationAt(i), | 154 current->LocationAt(i), |
| 151 slot_ix++); | 155 slot_ix++); |
| 152 } | 156 } |
| 153 | 157 |
| 154 // PC marker and caller FP. | 158 // PC marker and caller FP. |
| 155 builder->AddPcMarker(Function::Handle(current->code().function()), | 159 builder->AddPcMarker(Function::Handle(zone, current->code().function()), |
| 156 slot_ix++); | 160 slot_ix++); |
| 157 builder->AddCallerFp(slot_ix++); | 161 builder->AddCallerFp(slot_ix++); |
| 158 | 162 |
| 159 // Iterate on the outer environment. | 163 // Iterate on the outer environment. |
| 160 previous = current; | 164 previous = current; |
| 161 current = current->outer(); | 165 current = current->outer(); |
| 162 } | 166 } |
| 163 // The previous pointer is now the outermost environment. | 167 // The previous pointer is now the outermost environment. |
| 164 ASSERT(previous != NULL); | 168 ASSERT(previous != NULL); |
| 165 | 169 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 | 221 |
| 218 // Clobbers ECX. | 222 // Clobbers ECX. |
| 219 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 223 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| 220 TypeTestStubKind test_kind, | 224 TypeTestStubKind test_kind, |
| 221 Register instance_reg, | 225 Register instance_reg, |
| 222 Register type_arguments_reg, | 226 Register type_arguments_reg, |
| 223 Register temp_reg, | 227 Register temp_reg, |
| 224 Label* is_instance_lbl, | 228 Label* is_instance_lbl, |
| 225 Label* is_not_instance_lbl) { | 229 Label* is_not_instance_lbl) { |
| 226 const SubtypeTestCache& type_test_cache = | 230 const SubtypeTestCache& type_test_cache = |
| 227 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); | 231 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); |
| 228 const Immediate& raw_null = | 232 const Immediate& raw_null = |
| 229 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 233 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 230 __ LoadObject(temp_reg, type_test_cache); | 234 __ LoadObject(temp_reg, type_test_cache); |
| 231 __ pushl(temp_reg); // Subtype test cache. | 235 __ pushl(temp_reg); // Subtype test cache. |
| 232 __ pushl(instance_reg); // Instance. | 236 __ pushl(instance_reg); // Instance. |
| 233 if (test_kind == kTestTypeOneArg) { | 237 if (test_kind == kTestTypeOneArg) { |
| 234 ASSERT(type_arguments_reg == kNoRegister); | 238 ASSERT(type_arguments_reg == kNoRegister); |
| 235 __ pushl(raw_null); | 239 __ pushl(raw_null); |
| 236 __ call(&StubCode::Subtype1TestCacheLabel()); | 240 __ call(&StubCode::Subtype1TestCacheLabel()); |
| 237 } else if (test_kind == kTestTypeTwoArgs) { | 241 } else if (test_kind == kTestTypeTwoArgs) { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 261 // EAX: instance (must survive). | 265 // EAX: instance (must survive). |
| 262 // Clobbers ECX, EDI. | 266 // Clobbers ECX, EDI. |
| 263 RawSubtypeTestCache* | 267 RawSubtypeTestCache* |
| 264 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( | 268 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
| 265 intptr_t token_pos, | 269 intptr_t token_pos, |
| 266 const AbstractType& type, | 270 const AbstractType& type, |
| 267 Label* is_instance_lbl, | 271 Label* is_instance_lbl, |
| 268 Label* is_not_instance_lbl) { | 272 Label* is_not_instance_lbl) { |
| 269 __ Comment("InstantiatedTypeWithArgumentsTest"); | 273 __ Comment("InstantiatedTypeWithArgumentsTest"); |
| 270 ASSERT(type.IsInstantiated()); | 274 ASSERT(type.IsInstantiated()); |
| 271 const Class& type_class = Class::ZoneHandle(type.type_class()); | 275 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
| 272 ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass()); | 276 ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass()); |
| 273 const Register kInstanceReg = EAX; | 277 const Register kInstanceReg = EAX; |
| 274 Error& malformed_error = Error::Handle(); | 278 Error& malformed_error = Error::Handle(zone()); |
| 275 const Type& int_type = Type::Handle(Type::IntType()); | 279 const Type& int_type = Type::Handle(zone(), Type::IntType()); |
| 276 const bool smi_is_ok = int_type.IsSubtypeOf(type, &malformed_error); | 280 const bool smi_is_ok = int_type.IsSubtypeOf(type, &malformed_error); |
| 277 // Malformed type should have been handled at graph construction time. | 281 // Malformed type should have been handled at graph construction time. |
| 278 ASSERT(smi_is_ok || malformed_error.IsNull()); | 282 ASSERT(smi_is_ok || malformed_error.IsNull()); |
| 279 __ testl(kInstanceReg, Immediate(kSmiTagMask)); | 283 __ testl(kInstanceReg, Immediate(kSmiTagMask)); |
| 280 if (smi_is_ok) { | 284 if (smi_is_ok) { |
| 281 __ j(ZERO, is_instance_lbl); | 285 __ j(ZERO, is_instance_lbl); |
| 282 } else { | 286 } else { |
| 283 __ j(ZERO, is_not_instance_lbl); | 287 __ j(ZERO, is_not_instance_lbl); |
| 284 } | 288 } |
| 285 const intptr_t num_type_args = type_class.NumTypeArguments(); | 289 const intptr_t num_type_args = type_class.NumTypeArguments(); |
| 286 const intptr_t num_type_params = type_class.NumTypeParameters(); | 290 const intptr_t num_type_params = type_class.NumTypeParameters(); |
| 287 const intptr_t from_index = num_type_args - num_type_params; | 291 const intptr_t from_index = num_type_args - num_type_params; |
| 288 const TypeArguments& type_arguments = | 292 const TypeArguments& type_arguments = |
| 289 TypeArguments::ZoneHandle(type.arguments()); | 293 TypeArguments::ZoneHandle(zone(), type.arguments()); |
| 290 const bool is_raw_type = type_arguments.IsNull() || | 294 const bool is_raw_type = type_arguments.IsNull() || |
| 291 type_arguments.IsRaw(from_index, num_type_params); | 295 type_arguments.IsRaw(from_index, num_type_params); |
| 292 // Signature class is an instantiated parameterized type. | 296 // Signature class is an instantiated parameterized type. |
| 293 if (!type_class.IsSignatureClass()) { | 297 if (!type_class.IsSignatureClass()) { |
| 294 if (is_raw_type) { | 298 if (is_raw_type) { |
| 295 const Register kClassIdReg = ECX; | 299 const Register kClassIdReg = ECX; |
| 296 // dynamic type argument, check only classes. | 300 // dynamic type argument, check only classes. |
| 297 __ LoadClassId(kClassIdReg, kInstanceReg); | 301 __ LoadClassId(kClassIdReg, kInstanceReg); |
| 298 __ cmpl(kClassIdReg, Immediate(type_class.id())); | 302 __ cmpl(kClassIdReg, Immediate(type_class.id())); |
| 299 __ j(EQUAL, is_instance_lbl); | 303 __ j(EQUAL, is_instance_lbl); |
| 300 // List is a very common case. | 304 // List is a very common case. |
| 301 if (IsListClass(type_class)) { | 305 if (IsListClass(type_class)) { |
| 302 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); | 306 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); |
| 303 } | 307 } |
| 304 return GenerateSubtype1TestCacheLookup( | 308 return GenerateSubtype1TestCacheLookup( |
| 305 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 309 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 306 } | 310 } |
| 307 // If one type argument only, check if type argument is Object or dynamic. | 311 // If one type argument only, check if type argument is Object or dynamic. |
| 308 if (type_arguments.Length() == 1) { | 312 if (type_arguments.Length() == 1) { |
| 309 const AbstractType& tp_argument = AbstractType::ZoneHandle( | 313 const AbstractType& tp_argument = AbstractType::ZoneHandle( |
| 310 type_arguments.TypeAt(0)); | 314 zone(), type_arguments.TypeAt(0)); |
| 311 ASSERT(!tp_argument.IsMalformed()); | 315 ASSERT(!tp_argument.IsMalformed()); |
| 312 if (tp_argument.IsType()) { | 316 if (tp_argument.IsType()) { |
| 313 ASSERT(tp_argument.HasResolvedTypeClass()); | 317 ASSERT(tp_argument.HasResolvedTypeClass()); |
| 314 // Check if type argument is dynamic or Object. | 318 // Check if type argument is dynamic or Object. |
| 315 const Type& object_type = Type::Handle(Type::ObjectType()); | 319 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); |
| 316 if (object_type.IsSubtypeOf(tp_argument, NULL)) { | 320 if (object_type.IsSubtypeOf(tp_argument, NULL)) { |
| 317 // Instance class test only necessary. | 321 // Instance class test only necessary. |
| 318 return GenerateSubtype1TestCacheLookup( | 322 return GenerateSubtype1TestCacheLookup( |
| 319 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 323 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 320 } | 324 } |
| 321 } | 325 } |
| 322 } | 326 } |
| 323 } | 327 } |
| 324 // Regular subtype test cache involving instance's type arguments. | 328 // Regular subtype test cache involving instance's type arguments. |
| 325 const Register kTypeArgumentsReg = kNoRegister; | 329 const Register kTypeArgumentsReg = kNoRegister; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 350 // EAX: instance to test against (preserved). | 354 // EAX: instance to test against (preserved). |
| 351 // Clobbers ECX, EDI. | 355 // Clobbers ECX, EDI. |
| 352 // Returns true if there is a fallthrough. | 356 // Returns true if there is a fallthrough. |
| 353 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( | 357 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( |
| 354 intptr_t token_pos, | 358 intptr_t token_pos, |
| 355 const AbstractType& type, | 359 const AbstractType& type, |
| 356 Label* is_instance_lbl, | 360 Label* is_instance_lbl, |
| 357 Label* is_not_instance_lbl) { | 361 Label* is_not_instance_lbl) { |
| 358 __ Comment("InstantiatedTypeNoArgumentsTest"); | 362 __ Comment("InstantiatedTypeNoArgumentsTest"); |
| 359 ASSERT(type.IsInstantiated()); | 363 ASSERT(type.IsInstantiated()); |
| 360 const Class& type_class = Class::Handle(type.type_class()); | 364 const Class& type_class = Class::Handle(zone(), type.type_class()); |
| 361 ASSERT(type_class.NumTypeArguments() == 0); | 365 ASSERT(type_class.NumTypeArguments() == 0); |
| 362 | 366 |
| 363 const Register kInstanceReg = EAX; | 367 const Register kInstanceReg = EAX; |
| 364 __ testl(kInstanceReg, Immediate(kSmiTagMask)); | 368 __ testl(kInstanceReg, Immediate(kSmiTagMask)); |
| 365 // If instance is Smi, check directly. | 369 // If instance is Smi, check directly. |
| 366 const Class& smi_class = Class::Handle(Smi::Class()); | 370 const Class& smi_class = Class::Handle(zone(), Smi::Class()); |
| 367 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 371 if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()), |
| 368 type_class, | 372 type_class, |
| 369 TypeArguments::Handle(), | 373 TypeArguments::Handle(zone()), |
| 370 NULL)) { | 374 NULL)) { |
| 371 __ j(ZERO, is_instance_lbl); | 375 __ j(ZERO, is_instance_lbl); |
| 372 } else { | 376 } else { |
| 373 __ j(ZERO, is_not_instance_lbl); | 377 __ j(ZERO, is_not_instance_lbl); |
| 374 } | 378 } |
| 375 // Compare if the classes are equal. | 379 // Compare if the classes are equal. |
| 376 const Register kClassIdReg = ECX; | 380 const Register kClassIdReg = ECX; |
| 377 __ LoadClassId(kClassIdReg, kInstanceReg); | 381 __ LoadClassId(kClassIdReg, kInstanceReg); |
| 378 __ cmpl(kClassIdReg, Immediate(type_class.id())); | 382 __ cmpl(kClassIdReg, Immediate(type_class.id())); |
| 379 __ j(EQUAL, is_instance_lbl); | 383 __ j(EQUAL, is_instance_lbl); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 390 // Check if instance is a closure. | 394 // Check if instance is a closure. |
| 391 const Immediate& raw_null = | 395 const Immediate& raw_null = |
| 392 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 396 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 393 __ LoadClassById(EDI, kClassIdReg); | 397 __ LoadClassById(EDI, kClassIdReg); |
| 394 __ movl(EDI, FieldAddress(EDI, Class::signature_function_offset())); | 398 __ movl(EDI, FieldAddress(EDI, Class::signature_function_offset())); |
| 395 __ cmpl(EDI, raw_null); | 399 __ cmpl(EDI, raw_null); |
| 396 __ j(NOT_EQUAL, is_instance_lbl); | 400 __ j(NOT_EQUAL, is_instance_lbl); |
| 397 } | 401 } |
| 398 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 402 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
| 399 // Note that instance is not Smi (checked above). | 403 // Note that instance is not Smi (checked above). |
| 400 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { | 404 if (type.IsSubtypeOf(Type::Handle(zone(), Type::Number()), NULL)) { |
| 401 GenerateNumberTypeCheck( | 405 GenerateNumberTypeCheck( |
| 402 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 406 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); |
| 403 return false; | 407 return false; |
| 404 } | 408 } |
| 405 if (type.IsStringType()) { | 409 if (type.IsStringType()) { |
| 406 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); | 410 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); |
| 407 return false; | 411 return false; |
| 408 } | 412 } |
| 409 // Otherwise fallthrough. | 413 // Otherwise fallthrough. |
| 410 return true; | 414 return true; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 462 // Load instantiator (or null) and instantiator type arguments on stack. | 466 // Load instantiator (or null) and instantiator type arguments on stack. |
| 463 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 467 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
| 464 // EDX: instantiator type arguments. | 468 // EDX: instantiator type arguments. |
| 465 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 469 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
| 466 __ cmpl(EDX, raw_null); | 470 __ cmpl(EDX, raw_null); |
| 467 __ j(EQUAL, is_instance_lbl); | 471 __ j(EQUAL, is_instance_lbl); |
| 468 __ movl(EDI, | 472 __ movl(EDI, |
| 469 FieldAddress(EDX, TypeArguments::type_at_offset(type_param.index()))); | 473 FieldAddress(EDX, TypeArguments::type_at_offset(type_param.index()))); |
| 470 // EDI: concrete type of type. | 474 // EDI: concrete type of type. |
| 471 // Check if type argument is dynamic. | 475 // Check if type argument is dynamic. |
| 472 __ CompareObject(EDI, Type::ZoneHandle(Type::DynamicType())); | 476 __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::DynamicType())); |
| 473 __ j(EQUAL, is_instance_lbl); | 477 __ j(EQUAL, is_instance_lbl); |
| 474 __ CompareObject(EDI, Type::ZoneHandle(Type::ObjectType())); | 478 __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::ObjectType())); |
| 475 __ j(EQUAL, is_instance_lbl); | 479 __ j(EQUAL, is_instance_lbl); |
| 476 | 480 |
| 477 // For Smi check quickly against int and num interfaces. | 481 // For Smi check quickly against int and num interfaces. |
| 478 Label not_smi; | 482 Label not_smi; |
| 479 __ testl(EAX, Immediate(kSmiTagMask)); // Value is Smi? | 483 __ testl(EAX, Immediate(kSmiTagMask)); // Value is Smi? |
| 480 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); | 484 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
| 481 __ CompareObject(EDI, Type::ZoneHandle(Type::IntType())); | 485 __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::IntType())); |
| 482 __ j(EQUAL, is_instance_lbl); | 486 __ j(EQUAL, is_instance_lbl); |
| 483 __ CompareObject(EDI, Type::ZoneHandle(Type::Number())); | 487 __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::Number())); |
| 484 __ j(EQUAL, is_instance_lbl); | 488 __ j(EQUAL, is_instance_lbl); |
| 485 // Smi must be handled in runtime. | 489 // Smi must be handled in runtime. |
| 486 Label fall_through; | 490 Label fall_through; |
| 487 __ jmp(&fall_through); | 491 __ jmp(&fall_through); |
| 488 | 492 |
| 489 __ Bind(¬_smi); | 493 __ Bind(¬_smi); |
| 490 // EDX: instantiator type arguments. | 494 // EDX: instantiator type arguments. |
| 491 // EAX: instance. | 495 // EAX: instance. |
| 492 const Register kInstanceReg = EAX; | 496 const Register kInstanceReg = EAX; |
| 493 const Register kTypeArgumentsReg = EDX; | 497 const Register kTypeArgumentsReg = EDX; |
| 494 const Register kTempReg = EDI; | 498 const Register kTempReg = EDI; |
| 495 const SubtypeTestCache& type_test_cache = | 499 const SubtypeTestCache& type_test_cache = |
| 496 SubtypeTestCache::ZoneHandle( | 500 SubtypeTestCache::ZoneHandle(zone(), |
| 497 GenerateCallSubtypeTestStub(kTestTypeThreeArgs, | 501 GenerateCallSubtypeTestStub(kTestTypeThreeArgs, |
| 498 kInstanceReg, | 502 kInstanceReg, |
| 499 kTypeArgumentsReg, | 503 kTypeArgumentsReg, |
| 500 kTempReg, | 504 kTempReg, |
| 501 is_instance_lbl, | 505 is_instance_lbl, |
| 502 is_not_instance_lbl)); | 506 is_not_instance_lbl)); |
| 503 __ Bind(&fall_through); | 507 __ Bind(&fall_through); |
| 504 return type_test_cache.raw(); | 508 return type_test_cache.raw(); |
| 505 } | 509 } |
| 506 if (type.IsType()) { | 510 if (type.IsType()) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 537 const AbstractType& type, | 541 const AbstractType& type, |
| 538 Label* is_instance_lbl, | 542 Label* is_instance_lbl, |
| 539 Label* is_not_instance_lbl) { | 543 Label* is_not_instance_lbl) { |
| 540 __ Comment("InlineInstanceof"); | 544 __ Comment("InlineInstanceof"); |
| 541 if (type.IsVoidType()) { | 545 if (type.IsVoidType()) { |
| 542 // A non-null value is returned from a void function, which will result in a | 546 // A non-null value is returned from a void function, which will result in a |
| 543 // type error. A null value is handled prior to executing this inline code. | 547 // type error. A null value is handled prior to executing this inline code. |
| 544 return SubtypeTestCache::null(); | 548 return SubtypeTestCache::null(); |
| 545 } | 549 } |
| 546 if (type.IsInstantiated()) { | 550 if (type.IsInstantiated()) { |
| 547 const Class& type_class = Class::ZoneHandle(type.type_class()); | 551 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
| 548 // A class equality check is only applicable with a dst type of a | 552 // A class equality check is only applicable with a dst type of a |
| 549 // non-parameterized class, non-signature class, or with a raw dst type of | 553 // non-parameterized class, non-signature class, or with a raw dst type of |
| 550 // a parameterized class. | 554 // a parameterized class. |
| 551 if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) { | 555 if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) { |
| 552 return GenerateInstantiatedTypeWithArgumentsTest(token_pos, | 556 return GenerateInstantiatedTypeWithArgumentsTest(token_pos, |
| 553 type, | 557 type, |
| 554 is_instance_lbl, | 558 is_instance_lbl, |
| 555 is_not_instance_lbl); | 559 is_not_instance_lbl); |
| 556 // Fall through to runtime call. | 560 // Fall through to runtime call. |
| 557 } | 561 } |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 608 // return false here if the instance is null (and if the type is | 612 // return false here if the instance is null (and if the type is |
| 609 // instantiated). | 613 // instantiated). |
| 610 // We can only inline this null check if the type is instantiated at compile | 614 // We can only inline this null check if the type is instantiated at compile |
| 611 // time, since an uninstantiated type at compile time could be Object or | 615 // time, since an uninstantiated type at compile time could be Object or |
| 612 // dynamic at run time. | 616 // dynamic at run time. |
| 613 __ cmpl(EAX, raw_null); | 617 __ cmpl(EAX, raw_null); |
| 614 __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance); | 618 __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance); |
| 615 } | 619 } |
| 616 | 620 |
| 617 // Generate inline instanceof test. | 621 // Generate inline instanceof test. |
| 618 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 622 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 619 test_cache = GenerateInlineInstanceof(token_pos, type, | 623 test_cache = GenerateInlineInstanceof(token_pos, type, |
| 620 &is_instance, &is_not_instance); | 624 &is_instance, &is_not_instance); |
| 621 | 625 |
| 622 // test_cache is null if there is no fall-through. | 626 // test_cache is null if there is no fall-through. |
| 623 Label done; | 627 Label done; |
| 624 if (!test_cache.IsNull()) { | 628 if (!test_cache.IsNull()) { |
| 625 // Generate runtime call. | 629 // Generate runtime call. |
| 626 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 630 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
| 627 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. | 631 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. |
| 628 __ PushObject(Object::null_object()); // Make room for the result. | 632 __ PushObject(Object::null_object()); // Make room for the result. |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 709 // We should never return here. | 713 // We should never return here. |
| 710 __ int3(); | 714 __ int3(); |
| 711 | 715 |
| 712 __ Bind(&is_assignable); // For a null object. | 716 __ Bind(&is_assignable); // For a null object. |
| 713 __ popl(EDX); // Remove pushed instantiator type arguments. | 717 __ popl(EDX); // Remove pushed instantiator type arguments. |
| 714 __ popl(ECX); // Remove pushed instantiator. | 718 __ popl(ECX); // Remove pushed instantiator. |
| 715 return; | 719 return; |
| 716 } | 720 } |
| 717 | 721 |
| 718 // Generate inline type check, linking to runtime call if not assignable. | 722 // Generate inline type check, linking to runtime call if not assignable. |
| 719 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 723 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 720 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 724 test_cache = GenerateInlineInstanceof(token_pos, dst_type, |
| 721 &is_assignable, &runtime_call); | 725 &is_assignable, &runtime_call); |
| 722 | 726 |
| 723 __ Bind(&runtime_call); | 727 __ Bind(&runtime_call); |
| 724 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 728 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
| 725 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. | 729 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. |
| 726 __ PushObject(Object::null_object()); // Make room for the result. | 730 __ PushObject(Object::null_object()); // Make room for the result. |
| 727 __ pushl(EAX); // Push the source object. | 731 __ pushl(EAX); // Push the source object. |
| 728 __ PushObject(dst_type); // Push the type of the destination. | 732 __ PushObject(dst_type); // Push the type of the destination. |
| 729 __ pushl(ECX); // Instantiator. | 733 __ pushl(ECX); // Instantiator. |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 873 __ movl(EAX, Address(EDI, ArgumentsDescriptor::position_offset())); | 877 __ movl(EAX, Address(EDI, ArgumentsDescriptor::position_offset())); |
| 874 // EAX is arg_pos as Smi. | 878 // EAX is arg_pos as Smi. |
| 875 // Point to next named entry. | 879 // Point to next named entry. |
| 876 __ addl(EDI, Immediate(ArgumentsDescriptor::named_entry_size())); | 880 __ addl(EDI, Immediate(ArgumentsDescriptor::named_entry_size())); |
| 877 __ negl(EAX); | 881 __ negl(EAX); |
| 878 Address argument_addr(EBX, EAX, TIMES_2, 0); // EAX is a negative Smi. | 882 Address argument_addr(EBX, EAX, TIMES_2, 0); // EAX is a negative Smi. |
| 879 __ movl(EAX, argument_addr); | 883 __ movl(EAX, argument_addr); |
| 880 __ jmp(&assign_optional_parameter, Assembler::kNearJump); | 884 __ jmp(&assign_optional_parameter, Assembler::kNearJump); |
| 881 __ Bind(&load_default_value); | 885 __ Bind(&load_default_value); |
| 882 // Load EAX with default argument. | 886 // Load EAX with default argument. |
| 883 const Object& value = Object::ZoneHandle( | 887 const Object& value = Object::ZoneHandle(zone(), |
| 884 parsed_function().default_parameter_values().At( | 888 parsed_function().default_parameter_values().At( |
| 885 param_pos - num_fixed_params)); | 889 param_pos - num_fixed_params)); |
| 886 __ LoadObject(EAX, value); | 890 __ LoadObject(EAX, value); |
| 887 __ Bind(&assign_optional_parameter); | 891 __ Bind(&assign_optional_parameter); |
| 888 // Assign EAX to fp[kFirstLocalSlotFromFp - param_pos]. | 892 // Assign EAX to fp[kFirstLocalSlotFromFp - param_pos]. |
| 889 // We do not use the final allocation index of the variable here, i.e. | 893 // We do not use the final allocation index of the variable here, i.e. |
| 890 // scope->VariableAt(i)->index(), because captured variables still need | 894 // scope->VariableAt(i)->index(), because captured variables still need |
| 891 // to be copied to the context that is not yet allocated. | 895 // to be copied to the context that is not yet allocated. |
| 892 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 896 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 893 const Address param_addr(EBP, computed_param_pos * kWordSize); | 897 const Address param_addr(EBP, computed_param_pos * kWordSize); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 908 __ SmiUntag(ECX); | 912 __ SmiUntag(ECX); |
| 909 for (int i = 0; i < num_opt_pos_params; i++) { | 913 for (int i = 0; i < num_opt_pos_params; i++) { |
| 910 Label next_parameter; | 914 Label next_parameter; |
| 911 // Handle this optional positional parameter only if k or fewer positional | 915 // Handle this optional positional parameter only if k or fewer positional |
| 912 // arguments have been passed, where k is param_pos, the position of this | 916 // arguments have been passed, where k is param_pos, the position of this |
| 913 // optional parameter in the formal parameter list. | 917 // optional parameter in the formal parameter list. |
| 914 const int param_pos = num_fixed_params + i; | 918 const int param_pos = num_fixed_params + i; |
| 915 __ cmpl(ECX, Immediate(param_pos)); | 919 __ cmpl(ECX, Immediate(param_pos)); |
| 916 __ j(GREATER, &next_parameter, Assembler::kNearJump); | 920 __ j(GREATER, &next_parameter, Assembler::kNearJump); |
| 917 // Load EAX with default argument. | 921 // Load EAX with default argument. |
| 918 const Object& value = Object::ZoneHandle( | 922 const Object& value = Object::ZoneHandle(zone(), |
| 919 parsed_function().default_parameter_values().At(i)); | 923 parsed_function().default_parameter_values().At(i)); |
| 920 __ LoadObject(EAX, value); | 924 __ LoadObject(EAX, value); |
| 921 // Assign EAX to fp[kFirstLocalSlotFromFp - param_pos]. | 925 // Assign EAX to fp[kFirstLocalSlotFromFp - param_pos]. |
| 922 // We do not use the final allocation index of the variable here, i.e. | 926 // We do not use the final allocation index of the variable here, i.e. |
| 923 // scope->VariableAt(i)->index(), because captured variables still need | 927 // scope->VariableAt(i)->index(), because captured variables still need |
| 924 // to be copied to the context that is not yet allocated. | 928 // to be copied to the context that is not yet allocated. |
| 925 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 929 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 926 const Address param_addr(EBP, computed_param_pos * kWordSize); | 930 const Address param_addr(EBP, computed_param_pos * kWordSize); |
| 927 __ movl(param_addr, EAX); | 931 __ movl(param_addr, EAX); |
| 928 __ Bind(&next_parameter); | 932 __ Bind(&next_parameter); |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1222 __ Drop(argument_count); | 1226 __ Drop(argument_count); |
| 1223 } | 1227 } |
| 1224 | 1228 |
| 1225 | 1229 |
| 1226 void FlowGraphCompiler::EmitEdgeCounter() { | 1230 void FlowGraphCompiler::EmitEdgeCounter() { |
| 1227 // We do not check for overflow when incrementing the edge counter. The | 1231 // We do not check for overflow when incrementing the edge counter. The |
| 1228 // function should normally be optimized long before the counter can | 1232 // function should normally be optimized long before the counter can |
| 1229 // overflow; and though we do not reset the counters when we optimize or | 1233 // overflow; and though we do not reset the counters when we optimize or |
| 1230 // deoptimize, there is a bound on the number of | 1234 // deoptimize, there is a bound on the number of |
| 1231 // optimization/deoptimization cycles we will attempt. | 1235 // optimization/deoptimization cycles we will attempt. |
| 1232 const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld)); | 1236 const Array& counter = Array::ZoneHandle(zone(), Array::New(1, Heap::kOld)); |
| 1233 counter.SetAt(0, Smi::Handle(Smi::New(0))); | 1237 counter.SetAt(0, Smi::Handle(zone(), Smi::New(0))); |
| 1234 __ Comment("Edge counter"); | 1238 __ Comment("Edge counter"); |
| 1235 __ LoadObject(EAX, counter); | 1239 __ LoadObject(EAX, counter); |
| 1236 intptr_t increment_start = assembler_->CodeSize(); | 1240 intptr_t increment_start = assembler_->CodeSize(); |
| 1237 __ IncrementSmiField(FieldAddress(EAX, Array::element_offset(0)), 1); | 1241 __ IncrementSmiField(FieldAddress(EAX, Array::element_offset(0)), 1); |
| 1238 int32_t size = assembler_->CodeSize() - increment_start; | 1242 int32_t size = assembler_->CodeSize() - increment_start; |
| 1239 if (isolate()->edge_counter_increment_size() == -1) { | 1243 if (isolate()->edge_counter_increment_size() == -1) { |
| 1240 isolate()->set_edge_counter_increment_size(size); | 1244 isolate()->set_edge_counter_increment_size(size); |
| 1241 } else { | 1245 } else { |
| 1242 ASSERT(size == isolate()->edge_counter_increment_size()); | 1246 ASSERT(size == isolate()->edge_counter_increment_size()); |
| 1243 } | 1247 } |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1293 } | 1297 } |
| 1294 | 1298 |
| 1295 | 1299 |
| 1296 void FlowGraphCompiler::EmitMegamorphicInstanceCall( | 1300 void FlowGraphCompiler::EmitMegamorphicInstanceCall( |
| 1297 const ICData& ic_data, | 1301 const ICData& ic_data, |
| 1298 intptr_t argument_count, | 1302 intptr_t argument_count, |
| 1299 intptr_t deopt_id, | 1303 intptr_t deopt_id, |
| 1300 intptr_t token_pos, | 1304 intptr_t token_pos, |
| 1301 LocationSummary* locs) { | 1305 LocationSummary* locs) { |
| 1302 MegamorphicCacheTable* table = isolate()->megamorphic_cache_table(); | 1306 MegamorphicCacheTable* table = isolate()->megamorphic_cache_table(); |
| 1303 const String& name = String::Handle(ic_data.target_name()); | 1307 const String& name = String::Handle(zone(), ic_data.target_name()); |
| 1304 const Array& arguments_descriptor = | 1308 const Array& arguments_descriptor = |
| 1305 Array::ZoneHandle(ic_data.arguments_descriptor()); | 1309 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); |
| 1306 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1310 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
| 1307 const MegamorphicCache& cache = | 1311 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(), |
| 1308 MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor)); | 1312 table->Lookup(name, arguments_descriptor)); |
| 1309 const Register receiverR = EDI; | 1313 const Register receiverR = EDI; |
| 1310 const Register cacheR = EBX; | 1314 const Register cacheR = EBX; |
| 1311 const Register targetR = EBX; | 1315 const Register targetR = EBX; |
| 1312 __ movl(receiverR, Address(ESP, (argument_count - 1) * kWordSize)); | 1316 __ movl(receiverR, Address(ESP, (argument_count - 1) * kWordSize)); |
| 1313 __ LoadObject(cacheR, cache); | 1317 __ LoadObject(cacheR, cache); |
| 1314 | 1318 |
| 1315 if (FLAG_use_megamorphic_stub) { | 1319 if (FLAG_use_megamorphic_stub) { |
| 1316 __ call(&StubCode::MegamorphicLookupLabel()); | 1320 __ call(&StubCode::MegamorphicLookupLabel()); |
| 1317 } else { | 1321 } else { |
| 1318 StubCode::EmitMegamorphicLookup(assembler(), receiverR, cacheR, targetR); | 1322 StubCode::EmitMegamorphicLookup(assembler(), receiverR, cacheR, targetR); |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1503 intptr_t argument_count, | 1507 intptr_t argument_count, |
| 1504 const Array& argument_names, | 1508 const Array& argument_names, |
| 1505 Label* failed, | 1509 Label* failed, |
| 1506 Label* match_found, | 1510 Label* match_found, |
| 1507 intptr_t deopt_id, | 1511 intptr_t deopt_id, |
| 1508 intptr_t token_index, | 1512 intptr_t token_index, |
| 1509 LocationSummary* locs) { | 1513 LocationSummary* locs) { |
| 1510 ASSERT(is_optimizing()); | 1514 ASSERT(is_optimizing()); |
| 1511 __ Comment("EmitTestAndCall"); | 1515 __ Comment("EmitTestAndCall"); |
| 1512 const Array& arguments_descriptor = | 1516 const Array& arguments_descriptor = |
| 1513 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, | 1517 Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count, |
| 1514 argument_names)); | 1518 argument_names)); |
| 1515 // Load receiver into EAX. | 1519 // Load receiver into EAX. |
| 1516 __ movl(EAX, Address(ESP, (argument_count - 1) * kWordSize)); | 1520 __ movl(EAX, Address(ESP, (argument_count - 1) * kWordSize)); |
| 1517 __ LoadObject(EDX, arguments_descriptor); | 1521 __ LoadObject(EDX, arguments_descriptor); |
| 1518 | 1522 |
| 1519 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; | 1523 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; |
| 1520 const intptr_t kNumChecks = ic_data.NumberOfChecks(); | 1524 const intptr_t kNumChecks = ic_data.NumberOfChecks(); |
| 1521 | 1525 |
| 1522 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); | 1526 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); |
| 1523 | 1527 |
| 1524 Label after_smi_test; | 1528 Label after_smi_test; |
| 1525 __ testl(EAX, Immediate(kSmiTagMask)); | 1529 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1526 if (kFirstCheckIsSmi) { | 1530 if (kFirstCheckIsSmi) { |
| 1527 // Jump if receiver is not Smi. | 1531 // Jump if receiver is not Smi. |
| 1528 if (kNumChecks == 1) { | 1532 if (kNumChecks == 1) { |
| 1529 __ j(NOT_ZERO, failed); | 1533 __ j(NOT_ZERO, failed); |
| 1530 } else { | 1534 } else { |
| 1531 __ j(NOT_ZERO, &after_smi_test); | 1535 __ j(NOT_ZERO, &after_smi_test); |
| 1532 } | 1536 } |
| 1533 // Do not use the code from the function, but let the code be patched so | 1537 // Do not use the code from the function, but let the code be patched so |
| 1534 // that we can record the outgoing edges to other code. | 1538 // that we can record the outgoing edges to other code. |
| 1535 GenerateDartCall(deopt_id, | 1539 GenerateDartCall(deopt_id, |
| 1536 token_index, | 1540 token_index, |
| 1537 &StubCode::CallStaticFunctionLabel(), | 1541 &StubCode::CallStaticFunctionLabel(), |
| 1538 RawPcDescriptors::kOther, | 1542 RawPcDescriptors::kOther, |
| 1539 locs); | 1543 locs); |
| 1540 const Function& function = Function::Handle(ic_data.GetTargetAt(0)); | 1544 const Function& function = Function::Handle(zone(), ic_data.GetTargetAt(0)); |
| 1541 AddStaticCallTarget(function); | 1545 AddStaticCallTarget(function); |
| 1542 __ Drop(argument_count); | 1546 __ Drop(argument_count); |
| 1543 if (kNumChecks > 1) { | 1547 if (kNumChecks > 1) { |
| 1544 __ jmp(match_found); | 1548 __ jmp(match_found); |
| 1545 } | 1549 } |
| 1546 } else { | 1550 } else { |
| 1547 // Receiver is Smi, but Smi is not a valid class therefore fail. | 1551 // Receiver is Smi, but Smi is not a valid class therefore fail. |
| 1548 // (Smi class must be first in the list). | 1552 // (Smi class must be first in the list). |
| 1549 __ j(ZERO, failed); | 1553 __ j(ZERO, failed); |
| 1550 } | 1554 } |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1850 __ movups(reg, Address(ESP, 0)); | 1854 __ movups(reg, Address(ESP, 0)); |
| 1851 __ addl(ESP, Immediate(kFpuRegisterSize)); | 1855 __ addl(ESP, Immediate(kFpuRegisterSize)); |
| 1852 } | 1856 } |
| 1853 | 1857 |
| 1854 | 1858 |
| 1855 #undef __ | 1859 #undef __ |
| 1856 | 1860 |
| 1857 } // namespace dart | 1861 } // namespace dart |
| 1858 | 1862 |
| 1859 #endif // defined TARGET_ARCH_IA32 | 1863 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |