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

Side by Side Diff: src/hydrogen.cc

Issue 1199983002: [strong] Implement strong property access semantics (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: add TODOs Created 5 years, 5 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
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 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/hydrogen.h" 5 #include "src/hydrogen.h"
6 6
7 #include <sstream> 7 #include <sstream>
8 8
9 #include "src/v8.h" 9 #include "src/v8.h"
10 10
(...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after
676 HConstant* HGraph::GetConstant1() { 676 HConstant* HGraph::GetConstant1() {
677 return GetConstant(&constant_1_, 1); 677 return GetConstant(&constant_1_, 1);
678 } 678 }
679 679
680 680
681 HConstant* HGraph::GetConstantMinus1() { 681 HConstant* HGraph::GetConstantMinus1() {
682 return GetConstant(&constant_minus1_, -1); 682 return GetConstant(&constant_minus1_, -1);
683 } 683 }
684 684
685 685
686 HConstant* HGraph::GetConstantBool(bool value) {
687 return value ? GetConstantTrue() : GetConstantFalse();
688 }
689
690
686 #define DEFINE_GET_CONSTANT(Name, name, type, htype, boolean_value) \ 691 #define DEFINE_GET_CONSTANT(Name, name, type, htype, boolean_value) \
687 HConstant* HGraph::GetConstant##Name() { \ 692 HConstant* HGraph::GetConstant##Name() { \
688 if (!constant_##name##_.is_set()) { \ 693 if (!constant_##name##_.is_set()) { \
689 HConstant* constant = new(zone()) HConstant( \ 694 HConstant* constant = new(zone()) HConstant( \
690 Unique<Object>::CreateImmovable(isolate()->factory()->name##_value()), \ 695 Unique<Object>::CreateImmovable(isolate()->factory()->name##_value()), \
691 Unique<Map>::CreateImmovable(isolate()->factory()->type##_map()), \ 696 Unique<Map>::CreateImmovable(isolate()->factory()->type##_map()), \
692 false, \ 697 false, \
693 Representation::Tagged(), \ 698 Representation::Tagged(), \
694 htype, \ 699 htype, \
695 true, \ 700 true, \
(...skipping 964 matching lines...) Expand 10 before | Expand all | Expand 10 after
1660 // hash = hash * 2057; 1665 // hash = hash * 2057;
1661 hash = AddUncasted<HMul>(hash, Add<HConstant>(2057)); 1666 hash = AddUncasted<HMul>(hash, Add<HConstant>(2057));
1662 hash->ClearFlag(HValue::kCanOverflow); 1667 hash->ClearFlag(HValue::kCanOverflow);
1663 1668
1664 // hash = hash ^ (hash >> 16); 1669 // hash = hash ^ (hash >> 16);
1665 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(16)); 1670 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(16));
1666 return AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash); 1671 return AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
1667 } 1672 }
1668 1673
1669 1674
1670 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver, 1675 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(
1671 HValue* elements, 1676 HValue* receiver, HValue* elements, HValue* key, HValue* hash,
1672 HValue* key, 1677 LanguageMode language_mode) {
1673 HValue* hash) {
1674 HValue* capacity = 1678 HValue* capacity =
1675 Add<HLoadKeyed>(elements, Add<HConstant>(NameDictionary::kCapacityIndex), 1679 Add<HLoadKeyed>(elements, Add<HConstant>(NameDictionary::kCapacityIndex),
1676 nullptr, FAST_ELEMENTS); 1680 nullptr, FAST_ELEMENTS);
1677 1681
1678 HValue* mask = AddUncasted<HSub>(capacity, graph()->GetConstant1()); 1682 HValue* mask = AddUncasted<HSub>(capacity, graph()->GetConstant1());
1679 mask->ChangeRepresentation(Representation::Integer32()); 1683 mask->ChangeRepresentation(Representation::Integer32());
1680 mask->ClearFlag(HValue::kCanOverflow); 1684 mask->ClearFlag(HValue::kCanOverflow);
1681 1685
1682 HValue* entry = hash; 1686 HValue* entry = hash;
1683 HValue* count = graph()->GetConstant1(); 1687 HValue* count = graph()->GetConstant1();
(...skipping 22 matching lines...) Expand all
1706 HValue* candidate_key = 1710 HValue* candidate_key =
1707 Add<HLoadKeyed>(elements, key_index, nullptr, FAST_ELEMENTS); 1711 Add<HLoadKeyed>(elements, key_index, nullptr, FAST_ELEMENTS);
1708 IfBuilder if_undefined(this); 1712 IfBuilder if_undefined(this);
1709 if_undefined.If<HCompareObjectEqAndBranch>(candidate_key, 1713 if_undefined.If<HCompareObjectEqAndBranch>(candidate_key,
1710 graph()->GetConstantUndefined()); 1714 graph()->GetConstantUndefined());
1711 if_undefined.Then(); 1715 if_undefined.Then();
1712 { 1716 {
1713 // element == undefined means "not found". Call the runtime. 1717 // element == undefined means "not found". Call the runtime.
1714 // TODO(jkummerow): walk the prototype chain instead. 1718 // TODO(jkummerow): walk the prototype chain instead.
1715 Add<HPushArguments>(receiver, key); 1719 Add<HPushArguments>(receiver, key);
1716 Push(Add<HCallRuntime>(isolate()->factory()->empty_string(), 1720 Push(Add<HCallRuntime>(
1717 Runtime::FunctionForId(Runtime::kKeyedGetProperty), 1721 isolate()->factory()->empty_string(),
1718 2)); 1722 Runtime::FunctionForId(is_strong(language_mode)
1723 ? Runtime::kKeyedGetPropertyStrong
1724 : Runtime::kKeyedGetProperty),
1725 2));
1719 } 1726 }
1720 if_undefined.Else(); 1727 if_undefined.Else();
1721 { 1728 {
1722 IfBuilder if_match(this); 1729 IfBuilder if_match(this);
1723 if_match.If<HCompareObjectEqAndBranch>(candidate_key, key); 1730 if_match.If<HCompareObjectEqAndBranch>(candidate_key, key);
1724 if_match.Then(); 1731 if_match.Then();
1725 if_match.Else(); 1732 if_match.Else();
1726 1733
1727 // Update non-internalized string in the dictionary with internalized key? 1734 // Update non-internalized string in the dictionary with internalized key?
1728 IfBuilder if_update_with_internalized(this); 1735 IfBuilder if_update_with_internalized(this);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1766 IfBuilder details_compare(this); 1773 IfBuilder details_compare(this);
1767 details_compare.If<HCompareNumericAndBranch>( 1774 details_compare.If<HCompareNumericAndBranch>(
1768 details, graph()->GetConstant0(), Token::EQ); 1775 details, graph()->GetConstant0(), Token::EQ);
1769 details_compare.Then(); 1776 details_compare.Then();
1770 HValue* result_index = 1777 HValue* result_index =
1771 AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset + 1)); 1778 AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset + 1));
1772 result_index->ClearFlag(HValue::kCanOverflow); 1779 result_index->ClearFlag(HValue::kCanOverflow);
1773 Push(Add<HLoadKeyed>(elements, result_index, nullptr, FAST_ELEMENTS)); 1780 Push(Add<HLoadKeyed>(elements, result_index, nullptr, FAST_ELEMENTS));
1774 details_compare.Else(); 1781 details_compare.Else();
1775 Add<HPushArguments>(receiver, key); 1782 Add<HPushArguments>(receiver, key);
1776 Push(Add<HCallRuntime>(isolate()->factory()->empty_string(), 1783 Push(Add<HCallRuntime>(
1777 Runtime::FunctionForId(Runtime::kKeyedGetProperty), 1784 isolate()->factory()->empty_string(),
1778 2)); 1785 Runtime::FunctionForId(is_strong(language_mode)
1786 ? Runtime::kKeyedGetPropertyStrong
1787 : Runtime::kKeyedGetProperty),
1788 2));
1779 details_compare.End(); 1789 details_compare.End();
1780 1790
1781 found_key_match.Else(); 1791 found_key_match.Else();
1782 found_key_match.JoinContinuation(&return_or_loop_continuation); 1792 found_key_match.JoinContinuation(&return_or_loop_continuation);
1783 } 1793 }
1784 if_undefined.JoinContinuation(&return_or_loop_continuation); 1794 if_undefined.JoinContinuation(&return_or_loop_continuation);
1785 1795
1786 IfBuilder return_or_loop(this, &return_or_loop_continuation); 1796 IfBuilder return_or_loop(this, &return_or_loop_continuation);
1787 return_or_loop.Then(); 1797 return_or_loop.Then();
1788 probe_loop.Break(); 1798 probe_loop.Break();
(...skipping 4452 matching lines...) Expand 10 before | Expand all | Expand 10 after
6241 return false; 6251 return false;
6242 } 6252 }
6243 6253
6244 6254
6245 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic( 6255 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic(
6246 SmallMapList* maps) { 6256 SmallMapList* maps) {
6247 DCHECK(map_.is_identical_to(maps->first())); 6257 DCHECK(map_.is_identical_to(maps->first()));
6248 if (!CanAccessMonomorphic()) return false; 6258 if (!CanAccessMonomorphic()) return false;
6249 STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism); 6259 STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism);
6250 if (maps->length() > kMaxLoadPolymorphism) return false; 6260 if (maps->length() > kMaxLoadPolymorphism) return false;
6251
6252 HObjectAccess access = HObjectAccess::ForMap(); // bogus default 6261 HObjectAccess access = HObjectAccess::ForMap(); // bogus default
6253 if (GetJSObjectFieldAccess(&access)) { 6262 if (GetJSObjectFieldAccess(&access)) {
6254 for (int i = 1; i < maps->length(); ++i) { 6263 for (int i = 1; i < maps->length(); ++i) {
6255 PropertyAccessInfo test_info(builder_, access_type_, maps->at(i), name_); 6264 PropertyAccessInfo test_info(builder_, access_type_, maps->at(i), name_);
6256 HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default 6265 HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default
6257 if (!test_info.GetJSObjectFieldAccess(&test_access)) return false; 6266 if (!test_info.GetJSObjectFieldAccess(&test_access)) return false;
6258 if (!access.Equals(test_access)) return false; 6267 if (!access.Equals(test_access)) return false;
6259 } 6268 }
6260 return true; 6269 return true;
6261 } 6270 }
6262
6263 if (GetJSArrayBufferViewFieldAccess(&access)) { 6271 if (GetJSArrayBufferViewFieldAccess(&access)) {
6264 for (int i = 1; i < maps->length(); ++i) { 6272 for (int i = 1; i < maps->length(); ++i) {
6265 PropertyAccessInfo test_info(builder_, access_type_, maps->at(i), name_); 6273 PropertyAccessInfo test_info(builder_, access_type_, maps->at(i), name_);
6266 HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default 6274 HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default
6267 if (!test_info.GetJSArrayBufferViewFieldAccess(&test_access)) { 6275 if (!test_info.GetJSArrayBufferViewFieldAccess(&test_access)) {
6268 return false; 6276 return false;
6269 } 6277 }
6270 if (!access.Equals(test_access)) return false; 6278 if (!access.Equals(test_access)) return false;
6271 } 6279 }
6272 return true; 6280 return true;
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
6334 } 6342 }
6335 6343
6336 HValue* checked_holder = checked_object; 6344 HValue* checked_holder = checked_object;
6337 if (info->has_holder()) { 6345 if (info->has_holder()) {
6338 Handle<JSObject> prototype(JSObject::cast(info->map()->prototype())); 6346 Handle<JSObject> prototype(JSObject::cast(info->map()->prototype()));
6339 checked_holder = BuildCheckPrototypeMaps(prototype, info->holder()); 6347 checked_holder = BuildCheckPrototypeMaps(prototype, info->holder());
6340 } 6348 }
6341 6349
6342 if (!info->IsFound()) { 6350 if (!info->IsFound()) {
6343 DCHECK(info->IsLoad()); 6351 DCHECK(info->IsLoad());
6344 return graph()->GetConstantUndefined(); 6352 if (is_strong(function_language_mode())) {
6353 return New<HCallRuntime>(
6354 isolate()->factory()->empty_string(),
6355 Runtime::FunctionForId(Runtime::kThrowStrongModeImplicitConversion),
6356 0);
6357 } else {
6358 return graph()->GetConstantUndefined();
6359 }
6345 } 6360 }
6346 6361
6347 if (info->IsData()) { 6362 if (info->IsData()) {
6348 if (info->IsLoad()) { 6363 if (info->IsLoad()) {
6349 return BuildLoadNamedField(info, checked_holder); 6364 return BuildLoadNamedField(info, checked_holder);
6350 } else { 6365 } else {
6351 return BuildStoreNamedField(info, checked_object, value); 6366 return BuildStoreNamedField(info, checked_object, value);
6352 } 6367 }
6353 } 6368 }
6354 6369
(...skipping 676 matching lines...) Expand 10 before | Expand all | Expand 10 after
7031 Handle<TypeFeedbackVector> vector = 7046 Handle<TypeFeedbackVector> vector =
7032 handle(current_feedback_vector(), isolate()); 7047 handle(current_feedback_vector(), isolate());
7033 FeedbackVectorICSlot slot = expr->AsProperty()->PropertyFeedbackSlot(); 7048 FeedbackVectorICSlot slot = expr->AsProperty()->PropertyFeedbackSlot();
7034 7049
7035 if (!expr->AsProperty()->key()->IsPropertyName()) { 7050 if (!expr->AsProperty()->key()->IsPropertyName()) {
7036 // It's possible that a keyed load of a constant string was converted 7051 // It's possible that a keyed load of a constant string was converted
7037 // to a named load. Here, at the last minute, we need to make sure to 7052 // to a named load. Here, at the last minute, we need to make sure to
7038 // use a generic Keyed Load if we are using the type vector, because 7053 // use a generic Keyed Load if we are using the type vector, because
7039 // it has to share information with full code. 7054 // it has to share information with full code.
7040 HConstant* key = Add<HConstant>(name); 7055 HConstant* key = Add<HConstant>(name);
7041 HLoadKeyedGeneric* result = 7056 HLoadKeyedGeneric* result = New<HLoadKeyedGeneric>(
7042 New<HLoadKeyedGeneric>(object, key, PREMONOMORPHIC); 7057 object, key, function_language_mode(), PREMONOMORPHIC);
7043 result->SetVectorAndSlot(vector, slot); 7058 result->SetVectorAndSlot(vector, slot);
7044 return result; 7059 return result;
7045 } 7060 }
7046 7061
7047 HLoadNamedGeneric* result = 7062 HLoadNamedGeneric* result = New<HLoadNamedGeneric>(
7048 New<HLoadNamedGeneric>(object, name, PREMONOMORPHIC); 7063 object, name, function_language_mode(), PREMONOMORPHIC);
7049 result->SetVectorAndSlot(vector, slot); 7064 result->SetVectorAndSlot(vector, slot);
7050 return result; 7065 return result;
7051 } else { 7066 } else {
7052 return New<HStoreNamedGeneric>(object, name, value, 7067 return New<HStoreNamedGeneric>(object, name, value,
7053 function_language_mode(), PREMONOMORPHIC); 7068 function_language_mode(), PREMONOMORPHIC);
7054 } 7069 }
7055 } 7070 }
7056 7071
7057 7072
7058 7073
7059 HInstruction* HOptimizedGraphBuilder::BuildKeyedGeneric( 7074 HInstruction* HOptimizedGraphBuilder::BuildKeyedGeneric(
7060 PropertyAccessType access_type, 7075 PropertyAccessType access_type,
7061 Expression* expr, 7076 Expression* expr,
7062 HValue* object, 7077 HValue* object,
7063 HValue* key, 7078 HValue* key,
7064 HValue* value) { 7079 HValue* value) {
7065 if (access_type == LOAD) { 7080 if (access_type == LOAD) {
7066 InlineCacheState initial_state = expr->AsProperty()->GetInlineCacheState(); 7081 InlineCacheState initial_state = expr->AsProperty()->GetInlineCacheState();
7067 HLoadKeyedGeneric* result = 7082 HLoadKeyedGeneric* result = New<HLoadKeyedGeneric>(
7068 New<HLoadKeyedGeneric>(object, key, initial_state); 7083 object, key, function_language_mode(), initial_state);
7069 // HLoadKeyedGeneric with vector ics benefits from being encoded as 7084 // HLoadKeyedGeneric with vector ics benefits from being encoded as
7070 // MEGAMORPHIC because the vector/slot combo becomes unnecessary. 7085 // MEGAMORPHIC because the vector/slot combo becomes unnecessary.
7071 if (initial_state != MEGAMORPHIC) { 7086 if (initial_state != MEGAMORPHIC) {
7072 // We need to pass vector information. 7087 // We need to pass vector information.
7073 Handle<TypeFeedbackVector> vector = 7088 Handle<TypeFeedbackVector> vector =
7074 handle(current_feedback_vector(), isolate()); 7089 handle(current_feedback_vector(), isolate());
7075 FeedbackVectorICSlot slot = expr->AsProperty()->PropertyFeedbackSlot(); 7090 FeedbackVectorICSlot slot = expr->AsProperty()->PropertyFeedbackSlot();
7076 result->SetVectorAndSlot(vector, slot); 7091 result->SetVectorAndSlot(vector, slot);
7077 } 7092 }
7078 return result; 7093 return result;
(...skipping 2270 matching lines...) Expand 10 before | Expand all | Expand 10 after
9349 ComputeReceiverTypes(expr, receiver, &maps, zone()); 9364 ComputeReceiverTypes(expr, receiver, &maps, zone());
9350 9365
9351 if (prop->key()->IsPropertyName() && maps->length() > 0) { 9366 if (prop->key()->IsPropertyName() && maps->length() > 0) {
9352 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); 9367 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
9353 PropertyAccessInfo info(this, LOAD, maps->first(), name); 9368 PropertyAccessInfo info(this, LOAD, maps->first(), name);
9354 if (!info.CanAccessAsMonomorphic(maps)) { 9369 if (!info.CanAccessAsMonomorphic(maps)) {
9355 HandlePolymorphicCallNamed(expr, receiver, maps, name); 9370 HandlePolymorphicCallNamed(expr, receiver, maps, name);
9356 return; 9371 return;
9357 } 9372 }
9358 } 9373 }
9359
9360 HValue* key = NULL; 9374 HValue* key = NULL;
9361 if (!prop->key()->IsPropertyName()) { 9375 if (!prop->key()->IsPropertyName()) {
9362 CHECK_ALIVE(VisitForValue(prop->key())); 9376 CHECK_ALIVE(VisitForValue(prop->key()));
9363 key = Pop(); 9377 key = Pop();
9364 } 9378 }
9365 9379
9366 CHECK_ALIVE(PushLoad(prop, receiver, key)); 9380 CHECK_ALIVE(PushLoad(prop, receiver, key));
9367 HValue* function = Pop(); 9381 HValue* function = Pop();
9368 9382
9369 if (function->IsConstant() && 9383 if (function->IsConstant() &&
(...skipping 1420 matching lines...) Expand 10 before | Expand all | Expand 10 after
10790 // Only the stub is allowed to call into the runtime, since otherwise we would 10804 // Only the stub is allowed to call into the runtime, since otherwise we would
10791 // inline several instructions (including the two pushes) for every tagged 10805 // inline several instructions (including the two pushes) for every tagged
10792 // operation in optimized code, which is more expensive, than a stub call. 10806 // operation in optimized code, which is more expensive, than a stub call.
10793 if (graph()->info()->IsStub() && is_non_primitive) { 10807 if (graph()->info()->IsStub() && is_non_primitive) {
10794 HValue* function = 10808 HValue* function =
10795 AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op, strength)); 10809 AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op, strength));
10796 Add<HPushArguments>(left, right); 10810 Add<HPushArguments>(left, right);
10797 instr = AddUncasted<HInvokeFunction>(function, 2); 10811 instr = AddUncasted<HInvokeFunction>(function, 2);
10798 } else { 10812 } else {
10799 if (is_strong(strength) && Token::IsBitOp(op)) { 10813 if (is_strong(strength) && Token::IsBitOp(op)) {
10814 // TODO(conradw): This is not efficient, but is necessary to prevent
10815 // conversion of oddball values to numbers in strong mode. It would be
10816 // better to prevent the conversion rather than adding a runtime check.
10800 IfBuilder if_builder(this); 10817 IfBuilder if_builder(this);
10801 if_builder.If<HHasInstanceTypeAndBranch>(left, ODDBALL_TYPE); 10818 if_builder.If<HHasInstanceTypeAndBranch>(left, ODDBALL_TYPE);
10802 if_builder.OrIf<HHasInstanceTypeAndBranch>(right, ODDBALL_TYPE); 10819 if_builder.OrIf<HHasInstanceTypeAndBranch>(right, ODDBALL_TYPE);
10803 if_builder.Then(); 10820 if_builder.Then();
10804 Add<HCallRuntime>( 10821 Add<HCallRuntime>(
10805 isolate()->factory()->empty_string(), 10822 isolate()->factory()->empty_string(),
10806 Runtime::FunctionForId(Runtime::kThrowStrongModeImplicitConversion), 10823 Runtime::FunctionForId(Runtime::kThrowStrongModeImplicitConversion),
10807 0); 10824 0);
10808 if (!graph()->info()->IsStub()) { 10825 if (!graph()->info()->IsStub()) {
10809 Add<HSimulate>(opt_id, REMOVABLE_SIMULATE); 10826 Add<HSimulate>(opt_id, REMOVABLE_SIMULATE);
(...skipping 2415 matching lines...) Expand 10 before | Expand all | Expand 10 after
13225 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); 13242 isolate()->GetHTracer()->TraceHydrogen(name(), graph_);
13226 } 13243 }
13227 13244
13228 #ifdef DEBUG 13245 #ifdef DEBUG
13229 graph_->Verify(false); // No full verify. 13246 graph_->Verify(false); // No full verify.
13230 #endif 13247 #endif
13231 } 13248 }
13232 13249
13233 } // namespace internal 13250 } // namespace internal
13234 } // namespace v8 13251 } // namespace v8
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698