Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(687)

Side by Side Diff: runtime/vm/code_generator_x64.cc

Issue 10280007: Check upper bounds of type arguments when allocating objects of a generic type (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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_X64. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64.
6 #if defined(TARGET_ARCH_X64) 6 #if defined(TARGET_ARCH_X64)
7 7
8 #include "vm/code_generator.h" 8 #include "vm/code_generator.h"
9 9
10 #include "lib/error.h" 10 #include "lib/error.h"
(...skipping 1101 matching lines...) Expand 10 before | Expand all | Expand 10 after
1112 1112
1113 1113
1114 void CodeGenerator::VisitIncrOpLocalNode(IncrOpLocalNode* node) { 1114 void CodeGenerator::VisitIncrOpLocalNode(IncrOpLocalNode* node) {
1115 ASSERT((node->kind() == Token::kINCR) || (node->kind() == Token::kDECR)); 1115 ASSERT((node->kind() == Token::kINCR) || (node->kind() == Token::kDECR));
1116 MarkDeoptPoint(node->id(), node->token_index()); 1116 MarkDeoptPoint(node->id(), node->token_index());
1117 GenerateLoadVariable(RAX, node->local()); 1117 GenerateLoadVariable(RAX, node->local());
1118 if (!node->prefix() && IsResultNeeded(node)) { 1118 if (!node->prefix() && IsResultNeeded(node)) {
1119 // Preserve as result. 1119 // Preserve as result.
1120 __ pushq(RAX); 1120 __ pushq(RAX);
1121 } 1121 }
1122 const Immediate value = Immediate(reinterpret_cast<int64_t>(Smi::New(1)));
1123 const char* operator_name = (node->kind() == Token::kINCR) ? "+" : "-"; 1122 const char* operator_name = (node->kind() == Token::kINCR) ? "+" : "-";
1124 __ pushq(RAX); 1123 __ pushq(RAX);
1125 __ pushq(value); 1124 __ pushq(Immediate(Smi::RawValue(1)));
1126 GenerateBinaryOperatorCall(node->id(), node->token_index(), operator_name); 1125 GenerateBinaryOperatorCall(node->id(), node->token_index(), operator_name);
1127 // result is in RAX. 1126 // result is in RAX.
1128 if (FLAG_enable_type_checks) { 1127 if (FLAG_enable_type_checks) {
1129 GenerateAssertAssignable(node->id(), 1128 GenerateAssertAssignable(node->id(),
1130 node->token_index(), 1129 node->token_index(),
1131 NULL, 1130 NULL,
1132 node->local().type(), 1131 node->local().type(),
1133 node->local().name()); 1132 node->local().name());
1134 } 1133 }
1135 GenerateStoreVariable(node->local(), RAX, RDX); 1134 GenerateStoreVariable(node->local(), RAX, RDX);
(...skipping 11 matching lines...) Expand all
1147 MarkDeoptPoint(node->getter_id(), node->token_index()); 1146 MarkDeoptPoint(node->getter_id(), node->token_index());
1148 GenerateInstanceGetterCall(node->getter_id(), 1147 GenerateInstanceGetterCall(node->getter_id(),
1149 node->token_index(), 1148 node->token_index(),
1150 node->field_name()); 1149 node->field_name());
1151 // result is in RAX. 1150 // result is in RAX.
1152 __ popq(RDX); // Get receiver. 1151 __ popq(RDX); // Get receiver.
1153 if (!node->prefix() && IsResultNeeded(node)) { 1152 if (!node->prefix() && IsResultNeeded(node)) {
1154 // Preserve as result. 1153 // Preserve as result.
1155 __ pushq(RAX); // Preserve value as result. 1154 __ pushq(RAX); // Preserve value as result.
1156 } 1155 }
1157 const Immediate one_value = Immediate(reinterpret_cast<int64_t>(Smi::New(1)));
1158 const char* operator_name = (node->kind() == Token::kINCR) ? "+" : "-"; 1156 const char* operator_name = (node->kind() == Token::kINCR) ? "+" : "-";
1159 // RAX: Value. 1157 // RAX: Value.
1160 // RDX: Receiver. 1158 // RDX: Receiver.
1161 __ pushq(RDX); // Preserve receiver. 1159 __ pushq(RDX); // Preserve receiver.
1162 __ pushq(RAX); // Left operand. 1160 __ pushq(RAX); // Left operand.
1163 __ pushq(one_value); // Right operand. 1161 __ pushq(Immediate(Smi::RawValue(1))); // Right operand.
1164 GenerateBinaryOperatorCall(node->operator_id(), 1162 GenerateBinaryOperatorCall(node->operator_id(),
1165 node->token_index(), 1163 node->token_index(),
1166 operator_name); 1164 operator_name);
1167 __ popq(RDX); // Restore receiver. 1165 __ popq(RDX); // Restore receiver.
1168 if (IsResultNeeded(node) && node->prefix()) { 1166 if (IsResultNeeded(node) && node->prefix()) {
1169 // Value stored into field is the result. 1167 // Value stored into field is the result.
1170 __ pushq(RAX); 1168 __ pushq(RAX);
1171 } 1169 }
1172 __ pushq(RDX); // Receiver. 1170 __ pushq(RDX); // Receiver.
1173 __ pushq(RAX); // Value. 1171 __ pushq(RAX); // Value.
(...skipping 16 matching lines...) Expand all
1190 GenerateLoadIndexed(node->load_id(), node->token_index()); 1188 GenerateLoadIndexed(node->load_id(), node->token_index());
1191 // Result is in RAX. 1189 // Result is in RAX.
1192 if (!node->prefix() && IsResultNeeded(node)) { 1190 if (!node->prefix() && IsResultNeeded(node)) {
1193 // Preserve RAX as result. 1191 // Preserve RAX as result.
1194 __ popq(RDX); // Preserved index -> RDX. 1192 __ popq(RDX); // Preserved index -> RDX.
1195 __ popq(RCX); // Preserved array -> RCX. 1193 __ popq(RCX); // Preserved array -> RCX.
1196 __ pushq(RAX); // Preserve original value from indexed load. 1194 __ pushq(RAX); // Preserve original value from indexed load.
1197 __ pushq(RCX); // Array. 1195 __ pushq(RCX); // Array.
1198 __ pushq(RDX); // Index. 1196 __ pushq(RDX); // Index.
1199 } 1197 }
1200 const Immediate value = Immediate(reinterpret_cast<int64_t>(Smi::New(1)));
1201 const char* operator_name = (node->kind() == Token::kINCR) ? "+" : "-"; 1198 const char* operator_name = (node->kind() == Token::kINCR) ? "+" : "-";
1202 __ pushq(RAX); // Left operand. 1199 __ pushq(RAX); // Left operand.
1203 __ pushq(value); // Right operand. 1200 __ pushq(Immediate(Smi::RawValue(1))); // Right operand.
1204 GenerateBinaryOperatorCall(node->operator_id(), 1201 GenerateBinaryOperatorCall(node->operator_id(),
1205 node->token_index(), 1202 node->token_index(),
1206 operator_name); 1203 operator_name);
1207 __ pushq(RAX); 1204 __ pushq(RAX);
1208 // TOS(0): value, TOS(1): index, TOS(2): array. 1205 // TOS(0): value, TOS(1): index, TOS(2): array.
1209 GenerateStoreIndexed(node->store_id(), 1206 GenerateStoreIndexed(node->store_id(),
1210 node->token_index(), 1207 node->token_index(),
1211 node->prefix() && IsResultNeeded(node)); 1208 node->prefix() && IsResultNeeded(node));
1212 } 1209 }
1213 1210
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
1371 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); 1368 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
1372 __ CompareObject(RCX, *compare_class); 1369 __ CompareObject(RCX, *compare_class);
1373 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); 1370 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
1374 __ PushObject(negate_result ? bool_false : bool_true); 1371 __ PushObject(negate_result ? bool_false : bool_true);
1375 __ jmp(&done, Assembler::kNearJump); 1372 __ jmp(&done, Assembler::kNearJump);
1376 __ Bind(&runtime_call); 1373 __ Bind(&runtime_call);
1377 } 1374 }
1378 } 1375 }
1379 } 1376 }
1380 __ PushObject(Object::ZoneHandle()); // Make room for the result. 1377 __ PushObject(Object::ZoneHandle()); // Make room for the result.
1381 const Immediate location = 1378 const Immediate location = Immediate(Smi::RawValue(token_index));
1382 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index))); 1379 const Immediate node_id_as_smi = Immediate(Smi::RawValue(node_id));
1383 const Immediate node_id_as_smi =
1384 Immediate(reinterpret_cast<int64_t>(Smi::New(node_id)));
1385 __ pushq(location); // Push the source location. 1380 __ pushq(location); // Push the source location.
1386 __ pushq(node_id_as_smi); 1381 __ pushq(node_id_as_smi);
1387 __ pushq(RAX); // Push the instance. 1382 __ pushq(RAX); // Push the instance.
1388 __ PushObject(type); // Push the type. 1383 __ PushObject(type); // Push the type.
1389 if (!type.IsInstantiated()) { 1384 if (!type.IsInstantiated()) {
1390 GenerateInstantiatorTypeArguments(token_index); 1385 GenerateInstantiatorTypeArguments(token_index);
1391 } else { 1386 } else {
1392 __ pushq(raw_null); // Null instantiator. 1387 __ pushq(raw_null); // Null instantiator.
1393 } 1388 }
1394 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); 1389 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry);
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
1482 Label done, runtime_call; 1477 Label done, runtime_call;
1483 __ cmpq(RAX, raw_null); 1478 __ cmpq(RAX, raw_null);
1484 __ j(EQUAL, &done); 1479 __ j(EQUAL, &done);
1485 1480
1486 // Generate throw new TypeError() if the type is malformed. 1481 // Generate throw new TypeError() if the type is malformed.
1487 if (dst_type.IsMalformed()) { 1482 if (dst_type.IsMalformed()) {
1488 const Error& error = Error::Handle(dst_type.malformed_error()); 1483 const Error& error = Error::Handle(dst_type.malformed_error());
1489 const String& error_message = String::ZoneHandle( 1484 const String& error_message = String::ZoneHandle(
1490 String::NewSymbol(error.ToErrorCString())); 1485 String::NewSymbol(error.ToErrorCString()));
1491 __ PushObject(Object::ZoneHandle()); // Make room for the result. 1486 __ PushObject(Object::ZoneHandle()); // Make room for the result.
1492 const Immediate location = 1487 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location.
1493 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index)));
1494 __ pushq(location); // Push the source location.
1495 __ pushq(RAX); // Push the source object. 1488 __ pushq(RAX); // Push the source object.
1496 __ PushObject(dst_name); // Push the name of the destination. 1489 __ PushObject(dst_name); // Push the name of the destination.
1497 __ PushObject(error_message); 1490 __ PushObject(error_message);
1498 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); 1491 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry);
1499 // We should never return here. 1492 // We should never return here.
1500 __ int3(); 1493 __ int3();
1501 1494
1502 __ Bind(&done); // For a null object. 1495 __ Bind(&done); // For a null object.
1503 return; 1496 return;
1504 } 1497 }
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
1599 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); 1592 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
1600 __ movq(RCX, FieldAddress(RCX, Class::signature_function_offset())); 1593 __ movq(RCX, FieldAddress(RCX, Class::signature_function_offset()));
1601 __ cmpq(RCX, raw_null); 1594 __ cmpq(RCX, raw_null);
1602 __ j(NOT_EQUAL, &done); 1595 __ j(NOT_EQUAL, &done);
1603 } 1596 }
1604 } 1597 }
1605 } 1598 }
1606 } 1599 }
1607 __ Bind(&runtime_call); 1600 __ Bind(&runtime_call);
1608 __ PushObject(Object::ZoneHandle()); // Make room for the result. 1601 __ PushObject(Object::ZoneHandle()); // Make room for the result.
1609 const Immediate location = 1602 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location.
1610 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index))); 1603 __ pushq(Immediate(Smi::RawValue(node_id))); // node-id.
1611 const Immediate node_id_as_smi =
1612 Immediate(reinterpret_cast<int64_t>(Smi::New(node_id)));
1613 __ pushq(location); // Push the source location.
1614 __ pushq(node_id_as_smi); // node-id.
1615 __ pushq(RAX); // Push the source object. 1604 __ pushq(RAX); // Push the source object.
1616 __ PushObject(dst_type); // Push the type of the destination. 1605 __ PushObject(dst_type); // Push the type of the destination.
1617 if (!dst_type.IsInstantiated()) { 1606 if (!dst_type.IsInstantiated()) {
1618 GenerateInstantiatorTypeArguments(token_index); 1607 GenerateInstantiatorTypeArguments(token_index);
1619 } else { 1608 } else {
1620 __ pushq(raw_null); // Null instantiator. 1609 __ pushq(raw_null); // Null instantiator.
1621 } 1610 }
1622 __ PushObject(dst_name); // Push the name of the destination. 1611 __ PushObject(dst_name); // Push the name of the destination.
1623 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry); 1612 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry);
1624 // Pop the parameters supplied to the runtime entry. The result of the 1613 // Pop the parameters supplied to the runtime entry. The result of the
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
1669 // This check should pass if the receiver's class implements the interface 1658 // This check should pass if the receiver's class implements the interface
1670 // 'bool'. Check only class 'Bool' since it is the only legal implementation 1659 // 'bool'. Check only class 'Bool' since it is the only legal implementation
1671 // of the interface 'bool'. 1660 // of the interface 'bool'.
1672 const Class& bool_class = 1661 const Class& bool_class =
1673 Class::ZoneHandle(Isolate::Current()->object_store()->bool_class()); 1662 Class::ZoneHandle(Isolate::Current()->object_store()->bool_class());
1674 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); 1663 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
1675 __ CompareObject(RCX, bool_class); 1664 __ CompareObject(RCX, bool_class);
1676 __ j(EQUAL, &done, Assembler::kNearJump); 1665 __ j(EQUAL, &done, Assembler::kNearJump);
1677 1666
1678 __ Bind(&runtime_call); 1667 __ Bind(&runtime_call);
1679 const Immediate location = 1668 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location.
1680 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index)));
1681 __ pushq(location); // Push the source location.
1682 __ pushq(RAX); // Push the source object. 1669 __ pushq(RAX); // Push the source object.
1683 GenerateCallRuntime(node_id, token_index, kConditionTypeErrorRuntimeEntry); 1670 GenerateCallRuntime(node_id, token_index, kConditionTypeErrorRuntimeEntry);
1684 // We should never return here. 1671 // We should never return here.
1685 __ int3(); 1672 __ int3();
1686 1673
1687 __ Bind(&done); 1674 __ Bind(&done);
1688 } 1675 }
1689 1676
1690 1677
1691 void CodeGenerator::VisitComparisonNode(ComparisonNode* node) { 1678 void CodeGenerator::VisitComparisonNode(ComparisonNode* node) {
(...skipping 612 matching lines...) Expand 10 before | Expand all | Expand 10 after
2304 // Instantiate non-null type arguments. 2291 // Instantiate non-null type arguments.
2305 if (node->type_arguments().IsUninstantiatedIdentity()) { 2292 if (node->type_arguments().IsUninstantiatedIdentity()) {
2306 // Check if the instantiator type argument vector is a TypeArguments of a 2293 // Check if the instantiator type argument vector is a TypeArguments of a
2307 // matching length and, if so, use it as the instantiated type_arguments. 2294 // matching length and, if so, use it as the instantiated type_arguments.
2308 // No need to check RAX for null (again), because a null instance will 2295 // No need to check RAX for null (again), because a null instance will
2309 // have the wrong class (Null instead of TypeArguments). 2296 // have the wrong class (Null instead of TypeArguments).
2310 Label type_arguments_uninstantiated; 2297 Label type_arguments_uninstantiated;
2311 __ LoadObject(RCX, Class::ZoneHandle(Object::type_arguments_class())); 2298 __ LoadObject(RCX, Class::ZoneHandle(Object::type_arguments_class()));
2312 __ cmpq(RCX, FieldAddress(RAX, Object::class_offset())); 2299 __ cmpq(RCX, FieldAddress(RAX, Object::class_offset()));
2313 __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump); 2300 __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump);
2314 Immediate arguments_length = Immediate(reinterpret_cast<int64_t>( 2301 Immediate arguments_length =
2315 Smi::New(node->type_arguments().Length()))); 2302 Immediate(Smi::RawValue(node->type_arguments().Length()));
2316 __ cmpq(FieldAddress(RAX, TypeArguments::length_offset()), 2303 __ cmpq(FieldAddress(RAX, TypeArguments::length_offset()),
2317 arguments_length); 2304 arguments_length);
2318 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); 2305 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
2319 __ Bind(&type_arguments_uninstantiated); 2306 __ Bind(&type_arguments_uninstantiated);
2320 } 2307 }
2321 if (node->constructor().IsFactory()) { 2308 if (node->constructor().IsFactory()) {
2322 // A runtime call to instantiate the type arguments is required before 2309 // A runtime call to instantiate the type arguments is required before
2323 // calling the factory. 2310 // calling the factory.
2324 __ PushObject(Object::ZoneHandle()); // Make room for the result. 2311 __ PushObject(Object::ZoneHandle()); // Make room for the result.
2325 __ PushObject(node->type_arguments()); 2312 __ PushObject(node->type_arguments());
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
2371 } 2358 }
2372 return; 2359 return;
2373 } 2360 }
2374 2361
2375 const Class& cls = Class::ZoneHandle(node->constructor().owner()); 2362 const Class& cls = Class::ZoneHandle(node->constructor().owner());
2376 const bool requires_type_arguments = cls.HasTypeArguments(); 2363 const bool requires_type_arguments = cls.HasTypeArguments();
2377 GenerateTypeArguments(node, requires_type_arguments); 2364 GenerateTypeArguments(node, requires_type_arguments);
2378 2365
2379 // If cls is parameterized, the type arguments and the instantiator's 2366 // If cls is parameterized, the type arguments and the instantiator's
2380 // type arguments are on the stack. 2367 // type arguments are on the stack.
2381 const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls)); 2368 // In checked mode, if the type arguments are uninstantiated, they may need to
2382 const ExternalLabel label(cls.ToCString(), stub.EntryPoint()); 2369 // be checked against declared bounds at run time.
2383 GenerateCall(node->token_index(), &label, PcDescriptors::kOther); 2370 Error& malformed_error = Error::Handle();
2384 if (requires_type_arguments) { 2371 if (FLAG_enable_type_checks &&
2372 requires_type_arguments &&
2373 !node->type_arguments().IsNull() &&
2374 !node->type_arguments().IsInstantiated() &&
2375 !node->type_arguments().IsWithinBoundsOf(cls,
2376 node->type_arguments(),
2377 &malformed_error)) {
2378 // The uninstantiated type arguments cannot be verified to be within their
2379 // bounds at compile time, so verify them at runtime.
2380 // Although the type arguments may be uninstantiated at compile time, they
2381 // may represent the identity vector and may be replaced by the instantiated
2382 // type arguments of the instantiator at run time.
2383 __ popq(RCX); // Pop instantiator type arguments.
2384 __ popq(RAX); // Pop type arguments.
2385
2386 // Push the result place holder initialized to NULL.
2387 __ PushObject(Object::ZoneHandle());
2388 __ pushq(Immediate(Smi::RawValue(node->token_index())));
2389 __ PushObject(cls);
2390 __ pushq(RAX); // Push type arguments.
2391 __ pushq(RCX); // Push instantiator type arguments.
2392 GenerateCallRuntime(node->id(),
2393 node->token_index(),
2394 kAllocateObjectWithBoundsCheckRuntimeEntry);
2395 __ popq(RCX); // Pop instantiator type arguments.
2385 __ popq(RCX); // Pop type arguments. 2396 __ popq(RCX); // Pop type arguments.
2386 __ popq(RCX); // Pop instantiator type arguments. 2397 __ popq(RCX); // Pop class.
2398 __ popq(RCX); // Pop source location.
2399 __ popq(RAX); // Pop new instance.
2400 } else {
2401 const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls));
2402 const ExternalLabel label(cls.ToCString(), stub.EntryPoint());
2403 GenerateCall(node->token_index(), &label, PcDescriptors::kOther);
2404 if (requires_type_arguments) {
2405 __ popq(RCX); // Pop instantiator type arguments.
2406 __ popq(RCX); // Pop type arguments.
2407 }
2387 } 2408 }
2388 2409
2389 if (IsResultNeeded(node)) { 2410 if (IsResultNeeded(node)) {
2390 __ pushq(RAX); // Set up return value from allocate. 2411 __ pushq(RAX); // Set up return value from allocate.
2391 } 2412 }
2392 2413
2393 // First argument(this) for constructor call which follows. 2414 // First argument(this) for constructor call which follows.
2394 __ pushq(RAX); 2415 __ pushq(RAX);
2395 // Second argument is the implicit construction phase parameter. 2416 // Second argument is the implicit construction phase parameter.
2396 // Run both the constructor initializer list and the constructor body. 2417 // Run both the constructor initializer list and the constructor body.
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after
2731 const Error& error = Error::Handle( 2752 const Error& error = Error::Handle(
2732 Parser::FormatError(script, token_index, "Error", format, args)); 2753 Parser::FormatError(script, token_index, "Error", format, args));
2733 va_end(args); 2754 va_end(args);
2734 Isolate::Current()->long_jump_base()->Jump(1, error); 2755 Isolate::Current()->long_jump_base()->Jump(1, error);
2735 UNREACHABLE(); 2756 UNREACHABLE();
2736 } 2757 }
2737 2758
2738 } // namespace dart 2759 } // namespace dart
2739 2760
2740 #endif // defined TARGET_ARCH_X64 2761 #endif // defined TARGET_ARCH_X64
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698