Chromium Code Reviews

Side by Side Diff: src/wasm/function-body-decoder.cc

Issue 2640013003: [wasm] Some simplifications in function-body-decoder.cc. (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/signature.h" 5 #include "src/signature.h"
6 6
7 #include "src/bit-vector.h" 7 #include "src/bit-vector.h"
8 #include "src/flags.h" 8 #include "src/flags.h"
9 #include "src/handles.h" 9 #include "src/handles.h"
10 #include "src/zone/zone-containers.h" 10 #include "src/zone/zone-containers.h"
(...skipping 81 matching lines...)
92 }; 92 };
93 93
94 static Value* NO_VALUE = nullptr; 94 static Value* NO_VALUE = nullptr;
95 95
96 enum ControlKind { kControlIf, kControlBlock, kControlLoop, kControlTry }; 96 enum ControlKind { kControlIf, kControlBlock, kControlLoop, kControlTry };
97 97
98 // An entry on the control stack (i.e. if, block, loop). 98 // An entry on the control stack (i.e. if, block, loop).
99 struct Control { 99 struct Control {
100 const byte* pc; 100 const byte* pc;
101 ControlKind kind; 101 ControlKind kind;
102 int stack_depth; // stack height at the beginning of the construct. 102 size_t stack_depth; // stack height at the beginning of the construct.
103 SsaEnv* end_env; // end environment for the construct. 103 SsaEnv* end_env; // end environment for the construct.
104 SsaEnv* false_env; // false environment (only for if). 104 SsaEnv* false_env; // false environment (only for if).
105 TryInfo* try_info; // Information used for compiling try statements. 105 TryInfo* try_info; // Information used for compiling try statements.
106 int32_t previous_catch; // The previous Control (on the stack) with a catch. 106 int32_t previous_catch; // The previous Control (on the stack) with a catch.
107 107
108 // Values merged into the end of this control construct. 108 // Values merged into the end of this control construct.
109 MergeValues merge; 109 MergeValues merge;
110 110
111 inline bool is_if() const { return kind == kControlIf; } 111 inline bool is_if() const { return kind == kControlIf; }
112 inline bool is_block() const { return kind == kControlBlock; } 112 inline bool is_block() const { return kind == kControlBlock; }
113 inline bool is_loop() const { return kind == kControlLoop; } 113 inline bool is_loop() const { return kind == kControlLoop; }
114 inline bool is_try() const { return kind == kControlTry; } 114 inline bool is_try() const { return kind == kControlTry; }
115 115
116 // Named constructors. 116 // Named constructors.
117 static Control Block(const byte* pc, int stack_depth, SsaEnv* end_env, 117 static Control Block(const byte* pc, size_t stack_depth, SsaEnv* end_env,
118 int32_t previous_catch) { 118 int32_t previous_catch) {
119 return {pc, kControlBlock, stack_depth, end_env, 119 return {pc, kControlBlock, stack_depth, end_env,
120 nullptr, nullptr, previous_catch, {0, {NO_VALUE}}}; 120 nullptr, nullptr, previous_catch, {0, {NO_VALUE}}};
121 } 121 }
122 122
123 static Control If(const byte* pc, int stack_depth, SsaEnv* end_env, 123 static Control If(const byte* pc, size_t stack_depth, SsaEnv* end_env,
124 SsaEnv* false_env, int32_t previous_catch) { 124 SsaEnv* false_env, int32_t previous_catch) {
125 return {pc, kControlIf, stack_depth, end_env, 125 return {pc, kControlIf, stack_depth, end_env,
126 false_env, nullptr, previous_catch, {0, {NO_VALUE}}}; 126 false_env, nullptr, previous_catch, {0, {NO_VALUE}}};
127 } 127 }
128 128
129 static Control Loop(const byte* pc, int stack_depth, SsaEnv* end_env, 129 static Control Loop(const byte* pc, size_t stack_depth, SsaEnv* end_env,
130 int32_t previous_catch) { 130 int32_t previous_catch) {
131 return {pc, kControlLoop, stack_depth, end_env, 131 return {pc, kControlLoop, stack_depth, end_env,
132 nullptr, nullptr, previous_catch, {0, {NO_VALUE}}}; 132 nullptr, nullptr, previous_catch, {0, {NO_VALUE}}};
133 } 133 }
134 134
135 static Control Try(const byte* pc, int stack_depth, SsaEnv* end_env, 135 static Control Try(const byte* pc, size_t stack_depth, SsaEnv* end_env,
136 Zone* zone, SsaEnv* catch_env, int32_t previous_catch) { 136 Zone* zone, SsaEnv* catch_env, int32_t previous_catch) {
137 DCHECK_NOT_NULL(catch_env); 137 DCHECK_NOT_NULL(catch_env);
138 TryInfo* try_info = new (zone) TryInfo(catch_env); 138 TryInfo* try_info = new (zone) TryInfo(catch_env);
139 return {pc, kControlTry, stack_depth, end_env, 139 return {pc, kControlTry, stack_depth, end_env,
140 nullptr, try_info, previous_catch, {0, {NO_VALUE}}}; 140 nullptr, try_info, previous_catch, {0, {NO_VALUE}}};
141 } 141 }
142 }; 142 };
143 143
144 // Macros that build nodes only if there is a graph and the current SSA 144 // Macros that build nodes only if there is a graph and the current SSA
145 // environment is reachable from start. This avoids problems with malformed 145 // environment is reachable from start. This avoids problems with malformed
(...skipping 503 matching lines...)
649 } else if (c->merge.arity > 1) { 649 } else if (c->merge.arity > 1) {
650 c->merge.vals.array = zone_->NewArray<Value>(c->merge.arity); 650 c->merge.vals.array = zone_->NewArray<Value>(c->merge.arity);
651 for (unsigned i = 0; i < c->merge.arity; i++) { 651 for (unsigned i = 0; i < c->merge.arity; i++) {
652 c->merge.vals.array[i] = {pc_, nullptr, sig_->GetReturn(i)}; 652 c->merge.vals.array[i] = {pc_, nullptr, sig_->GetReturn(i)};
653 } 653 }
654 } 654 }
655 } 655 }
656 656
657 if (pc_ >= end_) return; // Nothing to do. 657 if (pc_ >= end_) return; // Nothing to do.
658 658
659 while (true) { // decoding loop. 659 while (true) { // decoding loop.
Clemens Hammacher 2017/01/18 15:46:26 You can also simplify this loop by removing the if
titzer 2017/01/18 17:22:17 Yeah, I originally did this on purpose as a manual
660 unsigned len = 1; 660 unsigned len = 1;
661 WasmOpcode opcode = static_cast<WasmOpcode>(*pc_); 661 WasmOpcode opcode = static_cast<WasmOpcode>(*pc_);
662 if (!WasmOpcodes::IsPrefixOpcode(opcode)) { 662 if (!WasmOpcodes::IsPrefixOpcode(opcode)) {
663 TRACE(" @%-8d #%02x:%-20s|", startrel(pc_), opcode, 663 TRACE(" @%-8d #%02x:%-20s|", startrel(pc_), opcode,
664 WasmOpcodes::ShortOpcodeName(opcode)); 664 WasmOpcodes::ShortOpcodeName(opcode));
665 } 665 }
666 666
667 FunctionSig* sig = WasmOpcodes::Signature(opcode); 667 FunctionSig* sig = WasmOpcodes::Signature(opcode);
668 if (sig) { 668 if (sig) {
669 BuildSimpleOperator(opcode, sig); 669 BuildSimpleOperator(opcode, sig);
(...skipping 134 matching lines...)
804 // A loop just leaves the values on the stack. 804 // A loop just leaves the values on the stack.
805 TypeCheckLoopFallThru(c); 805 TypeCheckLoopFallThru(c);
806 PopControl(); 806 PopControl();
807 SetEnv("loop:end", ssa_env_); 807 SetEnv("loop:end", ssa_env_);
808 break; 808 break;
809 } 809 }
810 if (c->is_if()) { 810 if (c->is_if()) {
811 if (c->false_env != nullptr) { 811 if (c->false_env != nullptr) {
812 // End the true branch of a one-armed if. 812 // End the true branch of a one-armed if.
813 Goto(c->false_env, c->end_env); 813 Goto(c->false_env, c->end_env);
814 if (ssa_env_->go() && 814 if (ssa_env_->go() && stack_.size() != c->stack_depth) {
815 static_cast<int>(stack_.size()) != c->stack_depth) {
816 error("end of if expected empty stack"); 815 error("end of if expected empty stack");
817 stack_.resize(c->stack_depth); 816 stack_.resize(c->stack_depth);
818 } 817 }
819 if (c->merge.arity > 0) { 818 if (c->merge.arity > 0) {
820 error("non-void one-armed if"); 819 error("non-void one-armed if");
821 } 820 }
822 name = "if:merge"; 821 name = "if:merge";
823 } else { 822 } else {
824 // End the false branch of a two-armed if. 823 // End the false branch of a two-armed if.
825 name = "if_else:merge"; 824 name = "if_else:merge";
(...skipping 13 matching lines...)
839 // Push the end values onto the stack. 838 // Push the end values onto the stack.
840 stack_.resize(c->stack_depth); 839 stack_.resize(c->stack_depth);
841 if (c->merge.arity == 1) { 840 if (c->merge.arity == 1) {
842 stack_.push_back(c->merge.vals.first); 841 stack_.push_back(c->merge.vals.first);
843 } else { 842 } else {
844 for (unsigned i = 0; i < c->merge.arity; i++) { 843 for (unsigned i = 0; i < c->merge.arity; i++) {
845 stack_.push_back(c->merge.vals.array[i]); 844 stack_.push_back(c->merge.vals.array[i]);
846 } 845 }
847 } 846 }
848 847
849 PopControl(); 848 if (control_.size() == 1) {
850
851 if (control_.empty()) {
852 // If the last (implicit) control was popped, check we are at end. 849 // If the last (implicit) control was popped, check we are at end.
rossberg 2017/01/18 16:21:42 Nit: s/was/is/
titzer 2017/01/18 17:22:17 Done.
853 if (pc_ + 1 != end_) { 850 if (pc_ + 1 != end_) {
854 error(pc_, pc_ + 1, "trailing code after function end"); 851 error(pc_, pc_ + 1, "trailing code after function end");
852 break;
855 } 853 }
856 last_end_found_ = true; 854 last_end_found_ = true;
857 if (ssa_env_->go()) { 855 if (ssa_env_->go()) {
858 // The result of the block is the return value. 856 // The result of the block is the return value.
859 TRACE(" @%-8d #xx:%-20s|", startrel(pc_), "ImplicitReturn"); 857 TRACE(" @%-8d #xx:%-20s|", startrel(pc_), "ImplicitReturn");
860 DoReturn(); 858 DoReturn();
861 TRACE("\n"); 859 TRACE("\n");
862 } 860 }
863 return;
864 } 861 }
862 PopControl();
865 break; 863 break;
866 } 864 }
867 case kExprSelect: { 865 case kExprSelect: {
868 Value cond = Pop(2, kWasmI32); 866 Value cond = Pop(2, kWasmI32);
869 Value fval = Pop(); 867 Value fval = Pop();
870 Value tval = Pop(); 868 Value tval = Pop();
871 if (tval.type == kWasmStmt || tval.type != fval.type) { 869 if (tval.type == kWasmStmt || tval.type != fval.type) {
872 if (tval.type != kWasmEnd && fval.type != kWasmEnd) { 870 if (tval.type != kWasmEnd && fval.type != kWasmEnd) {
873 error("type mismatch in select"); 871 error("type mismatch in select");
874 break; 872 break;
(...skipping 359 matching lines...)
1234 break; 1232 break;
1235 } 1233 }
1236 default: 1234 default:
1237 break; 1235 break;
1238 } 1236 }
1239 } 1237 }
1240 PrintF("\n"); 1238 PrintF("\n");
1241 } 1239 }
1242 #endif 1240 #endif
1243 pc_ += len; 1241 pc_ += len;
1244 if (pc_ >= end_) { 1242 if (pc_ >= end_) {
Clemens Hammacher 2017/01/18 15:46:26 This condition could go away then, just put this a
titzer 2017/01/18 17:22:17 Done.
1245 // End of code reached or exceeded. 1243 // End of code reached or exceeded.
1246 if (pc_ > end_ && ok()) error("Beyond end of code"); 1244 if (pc_ > end_ && ok()) error("Beyond end of code");
1247 return; 1245 return;
1248 } 1246 }
1249 } // end decode loop 1247 } // end decode loop
1250 } 1248 }
1251 1249
1252 void EndControl() { ssa_env_->Kill(SsaEnv::kControlEnd); } 1250 void EndControl() { ssa_env_->Kill(SsaEnv::kControlEnd); }
1253 1251
1254 void SetBlockType(Control* c, BlockTypeOperand& operand) { 1252 void SetBlockType(Control* c, BlockTypeOperand& operand) {
(...skipping 24 matching lines...)
1279 } 1277 }
1280 return nullptr; 1278 return nullptr;
1281 } 1279 }
1282 } 1280 }
1283 1281
1284 ValueType GetReturnType(FunctionSig* sig) { 1282 ValueType GetReturnType(FunctionSig* sig) {
1285 return sig->return_count() == 0 ? kWasmStmt : sig->GetReturn(); 1283 return sig->return_count() == 0 ? kWasmStmt : sig->GetReturn();
1286 } 1284 }
1287 1285
1288 void PushBlock(SsaEnv* end_env) { 1286 void PushBlock(SsaEnv* end_env) {
1289 const int stack_depth = static_cast<int>(stack_.size());
1290 control_.emplace_back( 1287 control_.emplace_back(
1291 Control::Block(pc_, stack_depth, end_env, current_catch_)); 1288 Control::Block(pc_, stack_.size(), end_env, current_catch_));
1292 } 1289 }
1293 1290
1294 void PushLoop(SsaEnv* end_env) { 1291 void PushLoop(SsaEnv* end_env) {
1295 const int stack_depth = static_cast<int>(stack_.size());
1296 control_.emplace_back( 1292 control_.emplace_back(
1297 Control::Loop(pc_, stack_depth, end_env, current_catch_)); 1293 Control::Loop(pc_, stack_.size(), end_env, current_catch_));
1298 } 1294 }
1299 1295
1300 void PushIf(SsaEnv* end_env, SsaEnv* false_env) { 1296 void PushIf(SsaEnv* end_env, SsaEnv* false_env) {
1301 const int stack_depth = static_cast<int>(stack_.size());
1302 control_.emplace_back( 1297 control_.emplace_back(
1303 Control::If(pc_, stack_depth, end_env, false_env, current_catch_)); 1298 Control::If(pc_, stack_.size(), end_env, false_env, current_catch_));
1304 } 1299 }
1305 1300
1306 void PushTry(SsaEnv* end_env, SsaEnv* catch_env) { 1301 void PushTry(SsaEnv* end_env, SsaEnv* catch_env) {
1307 const int stack_depth = static_cast<int>(stack_.size()); 1302 control_.emplace_back(Control::Try(pc_, stack_.size(), end_env, zone_,
1308 control_.emplace_back(Control::Try(pc_, stack_depth, end_env, zone_,
1309 catch_env, current_catch_)); 1303 catch_env, current_catch_));
1310 current_catch_ = static_cast<int32_t>(control_.size() - 1); 1304 current_catch_ = static_cast<int32_t>(control_.size() - 1);
1311 } 1305 }
1312 1306
1313 void PopControl() { control_.pop_back(); } 1307 void PopControl() { control_.pop_back(); }
1314 1308
1315 int DecodeLoadMem(ValueType type, MachineType mem_type) { 1309 int DecodeLoadMem(ValueType type, MachineType mem_type) {
1316 if (!CheckHasMemory()) return 0; 1310 if (!CheckHasMemory()) return 0;
1317 MemoryAccessOperand operand(this, pc_, 1311 MemoryAccessOperand operand(this, pc_,
1318 ElementSizeLog2Of(mem_type.representation())); 1312 ElementSizeLog2Of(mem_type.representation()));
(...skipping 105 matching lines...)
1424 Push(sig->GetReturn(i), rets ? rets[i] : nullptr); 1418 Push(sig->GetReturn(i), rets ? rets[i] : nullptr);
1425 } 1419 }
1426 } 1420 }
1427 1421
1428 const char* SafeOpcodeNameAt(const byte* pc) { 1422 const char* SafeOpcodeNameAt(const byte* pc) {
1429 if (pc >= end_) return "<end>"; 1423 if (pc >= end_) return "<end>";
1430 return WasmOpcodes::ShortOpcodeName(static_cast<WasmOpcode>(*pc)); 1424 return WasmOpcodes::ShortOpcodeName(static_cast<WasmOpcode>(*pc));
1431 } 1425 }
1432 1426
1433 Value Pop(int index, ValueType expected) { 1427 Value Pop(int index, ValueType expected) {
1434 if (!ssa_env_->go()) {
1435 // Unreachable code is essentially not typechecked.
1436 return {pc_, nullptr, expected};
1437 }
1438 Value val = Pop(); 1428 Value val = Pop();
1439 if (val.type != expected) { 1429 if (val.type != expected) {
1440 if (val.type != kWasmEnd) { 1430 if (val.type != kWasmEnd) {
1441 error(pc_, val.pc, "%s[%d] expected type %s, found %s of type %s", 1431 error(pc_, val.pc, "%s[%d] expected type %s, found %s of type %s",
1442 SafeOpcodeNameAt(pc_), index, WasmOpcodes::TypeName(expected), 1432 SafeOpcodeNameAt(pc_), index, WasmOpcodes::TypeName(expected),
1443 SafeOpcodeNameAt(val.pc), WasmOpcodes::TypeName(val.type)); 1433 SafeOpcodeNameAt(val.pc), WasmOpcodes::TypeName(val.type));
1444 } 1434 }
1445 } 1435 }
1446 return val; 1436 return val;
1447 } 1437 }
1448 1438
1449 Value Pop() { 1439 Value Pop() {
1450 if (!ssa_env_->go()) {
1451 // Unreachable code is essentially not typechecked.
1452 return {pc_, nullptr, kWasmEnd};
1453 }
1454 size_t limit = control_.empty() ? 0 : control_.back().stack_depth; 1440 size_t limit = control_.empty() ? 0 : control_.back().stack_depth;
1455 if (stack_.size() <= limit) { 1441 if (stack_.size() <= limit) {
1456 Value val = {pc_, nullptr, kWasmStmt}; 1442 Value val = {pc_, nullptr, kWasmEnd};
1457 error(pc_, pc_, "%s found empty stack", SafeOpcodeNameAt(pc_)); 1443 if (ssa_env_->go()) {
1444 // Popping past the current control start in reachable code.
1445 error(pc_, pc_, "%s found empty stack", SafeOpcodeNameAt(pc_));
1446 }
1458 return val; 1447 return val;
1459 } 1448 }
1460 Value val = stack_.back(); 1449 Value val = stack_.back();
1461 stack_.pop_back(); 1450 stack_.pop_back();
1462 return val; 1451 return val;
1463 } 1452 }
1464 1453
1465 Value PopUpTo(int stack_depth) {
1466 if (!ssa_env_->go()) {
1467 // Unreachable code is essentially not typechecked.
1468 return {pc_, nullptr, kWasmEnd};
1469 }
1470 if (stack_depth == static_cast<int>(stack_.size())) {
1471 Value val = {pc_, nullptr, kWasmStmt};
1472 return val;
1473 } else {
1474 DCHECK_LE(stack_depth, stack_.size());
1475 Value val = Pop();
1476 stack_.resize(stack_depth);
1477 return val;
1478 }
1479 }
1480
1481 int baserel(const byte* ptr) { 1454 int baserel(const byte* ptr) {
1482 return base_ ? static_cast<int>(ptr - base_) : 0; 1455 return base_ ? static_cast<int>(ptr - base_) : 0;
1483 } 1456 }
1484 1457
1485 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); } 1458 int startrel(const byte* ptr) { return static_cast<int>(ptr - start_); }
1486 1459
1487 void BreakTo(unsigned depth) { 1460 void BreakTo(unsigned depth) {
1488 if (!ssa_env_->go()) return; 1461 if (!ssa_env_->go()) return;
1489 Control* c = &control_[control_.size() - depth - 1]; 1462 Control* c = &control_[control_.size() - depth - 1];
1490 if (c->is_loop()) { 1463 if (c->is_loop()) {
(...skipping 10 matching lines...)
1501 return; 1474 return;
1502 } 1475 }
1503 MergeValuesInto(c); 1476 MergeValuesInto(c);
1504 } 1477 }
1505 } 1478 }
1506 1479
1507 void FallThruTo(Control* c) { 1480 void FallThruTo(Control* c) {
1508 if (!ssa_env_->go()) return; 1481 if (!ssa_env_->go()) return;
1509 // Merge the value(s) into the end of the block. 1482 // Merge the value(s) into the end of the block.
1510 int arity = static_cast<int>(c->merge.arity); 1483 int arity = static_cast<int>(c->merge.arity);
1511 if (c->stack_depth + arity != static_cast<int>(stack_.size())) { 1484 if (c->stack_depth + arity != stack_.size()) {
1512 error(pc_, pc_, "expected %d elements on the stack for fallthru to @%d", 1485 error(pc_, pc_, "expected %d elements on the stack for fallthru to @%d",
1513 arity, startrel(c->pc)); 1486 arity, startrel(c->pc));
1514 return; 1487 return;
1515 } 1488 }
1516 MergeValuesInto(c); 1489 MergeValuesInto(c);
1517 } 1490 }
1518 1491
1519 inline Value& GetMergeValueFromStack(Control* c, int i) { 1492 inline Value& GetMergeValueFromStack(Control* c, int i) {
1520 return stack_[stack_.size() - c->merge.arity + i]; 1493 return stack_[stack_.size() - c->merge.arity + i];
1521 } 1494 }
1522 1495
1523 void TypeCheckLoopFallThru(Control* c) { 1496 void TypeCheckLoopFallThru(Control* c) {
1524 if (!ssa_env_->go()) return; 1497 if (!ssa_env_->go()) return;
1525 // Fallthru must match arity exactly. 1498 // Fallthru must match arity exactly.
1526 int arity = static_cast<int>(c->merge.arity); 1499 int arity = static_cast<int>(c->merge.arity);
1527 if (c->stack_depth + arity != static_cast<int>(stack_.size())) { 1500 if (c->stack_depth + arity != stack_.size()) {
1528 error(pc_, pc_, "expected %d elements on the stack for fallthru to @%d", 1501 error(pc_, pc_, "expected %d elements on the stack for fallthru to @%d",
1529 arity, startrel(c->pc)); 1502 arity, startrel(c->pc));
1530 return; 1503 return;
1531 } 1504 }
1532 // Typecheck the values left on the stack. 1505 // Typecheck the values left on the stack.
1533 for (unsigned i = 0; i < c->merge.arity; i++) { 1506 for (unsigned i = 0; i < c->merge.arity; i++) {
1534 Value& val = GetMergeValueFromStack(c, i); 1507 Value& val = GetMergeValueFromStack(c, i);
1535 Value& old = 1508 Value& old =
1536 c->merge.arity == 1 ? c->merge.vals.first : c->merge.vals.array[i]; 1509 c->merge.arity == 1 ? c->merge.vals.first : c->merge.vals.array[i];
1537 if (val.type != old.type) { 1510 if (val.type != old.type) {
(...skipping 499 matching lines...)
2037 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, 2010 BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals,
2038 const byte* start, const byte* end) { 2011 const byte* start, const byte* end) {
2039 Decoder decoder(start, end); 2012 Decoder decoder(start, end);
2040 return WasmDecoder::AnalyzeLoopAssignment(&decoder, start, 2013 return WasmDecoder::AnalyzeLoopAssignment(&decoder, start,
2041 static_cast<int>(num_locals), zone); 2014 static_cast<int>(num_locals), zone);
2042 } 2015 }
2043 2016
2044 } // namespace wasm 2017 } // namespace wasm
2045 } // namespace internal 2018 } // namespace internal
2046 } // namespace v8 2019 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine