Upgrade V8 to 5.1.281.57 DO NOT MERGE
FPIIM-449
Change-Id: Id981b686b4d587ac31697662eb98bb34be42ad90
(cherry picked from commit 3b9bc31999c9787eb726ecdbfd5796bfdec32a18)
diff --git a/src/compiler/wasm-compiler.cc b/src/compiler/wasm-compiler.cc
index 9c3858d..93d5a08 100644
--- a/src/compiler/wasm-compiler.cc
+++ b/src/compiler/wasm-compiler.cc
@@ -6,6 +6,7 @@
#include "src/isolate-inl.h"
+#include "src/base/platform/elapsed-timer.h"
#include "src/base/platform/platform.h"
#include "src/compiler/access-builder.h"
@@ -71,28 +72,8 @@
}
}
-
-enum TrapReason {
- kTrapUnreachable,
- kTrapMemOutOfBounds,
- kTrapDivByZero,
- kTrapDivUnrepresentable,
- kTrapRemByZero,
- kTrapFloatUnrepresentable,
- kTrapFuncInvalid,
- kTrapFuncSigMismatch,
- kTrapCount
-};
-
-
-static const char* kTrapMessages[] = {
- "unreachable", "memory access out of bounds",
- "divide by zero", "divide result unrepresentable",
- "remainder by zero", "integer result unrepresentable",
- "invalid function", "function signature mismatch"};
} // namespace
-
// A helper that handles building graph fragments for trapping.
// To avoid generating a ton of redundant code that just calls the runtime
// to trap, we generate a per-trap-reason block of code that all trap sites
@@ -103,17 +84,17 @@
: builder_(builder),
jsgraph_(builder->jsgraph()),
graph_(builder->jsgraph() ? builder->jsgraph()->graph() : nullptr) {
- for (int i = 0; i < kTrapCount; i++) traps_[i] = nullptr;
+ for (int i = 0; i < wasm::kTrapCount; i++) traps_[i] = nullptr;
}
// Make the current control path trap to unreachable.
- void Unreachable() { ConnectTrap(kTrapUnreachable); }
+ void Unreachable() { ConnectTrap(wasm::kTrapUnreachable); }
// Always trap with the given reason.
- void TrapAlways(TrapReason reason) { ConnectTrap(reason); }
+ void TrapAlways(wasm::TrapReason reason) { ConnectTrap(reason); }
// Add a check that traps if {node} is equal to {val}.
- Node* TrapIfEq32(TrapReason reason, Node* node, int32_t val) {
+ Node* TrapIfEq32(wasm::TrapReason reason, Node* node, int32_t val) {
Int32Matcher m(node);
if (m.HasValue() && !m.Is(val)) return graph()->start();
if (val == 0) {
@@ -127,12 +108,12 @@
}
// Add a check that traps if {node} is zero.
- Node* ZeroCheck32(TrapReason reason, Node* node) {
+ Node* ZeroCheck32(wasm::TrapReason reason, Node* node) {
return TrapIfEq32(reason, node, 0);
}
// Add a check that traps if {node} is equal to {val}.
- Node* TrapIfEq64(TrapReason reason, Node* node, int64_t val) {
+ Node* TrapIfEq64(wasm::TrapReason reason, Node* node, int64_t val) {
Int64Matcher m(node);
if (m.HasValue() && !m.Is(val)) return graph()->start();
AddTrapIfTrue(reason,
@@ -142,22 +123,22 @@
}
// Add a check that traps if {node} is zero.
- Node* ZeroCheck64(TrapReason reason, Node* node) {
+ Node* ZeroCheck64(wasm::TrapReason reason, Node* node) {
return TrapIfEq64(reason, node, 0);
}
// Add a trap if {cond} is true.
- void AddTrapIfTrue(TrapReason reason, Node* cond) {
+ void AddTrapIfTrue(wasm::TrapReason reason, Node* cond) {
AddTrapIf(reason, cond, true);
}
// Add a trap if {cond} is false.
- void AddTrapIfFalse(TrapReason reason, Node* cond) {
+ void AddTrapIfFalse(wasm::TrapReason reason, Node* cond) {
AddTrapIf(reason, cond, false);
}
// Add a trap if {cond} is true or false according to {iftrue}.
- void AddTrapIf(TrapReason reason, Node* cond, bool iftrue) {
+ void AddTrapIf(wasm::TrapReason reason, Node* cond, bool iftrue) {
Node** effect_ptr = builder_->effect_;
Node** control_ptr = builder_->control_;
Node* before = *effect_ptr;
@@ -198,14 +179,14 @@
WasmGraphBuilder* builder_;
JSGraph* jsgraph_;
Graph* graph_;
- Node* traps_[kTrapCount];
- Node* effects_[kTrapCount];
+ Node* traps_[wasm::kTrapCount];
+ Node* effects_[wasm::kTrapCount];
JSGraph* jsgraph() { return jsgraph_; }
Graph* graph() { return jsgraph_->graph(); }
CommonOperatorBuilder* common() { return jsgraph()->common(); }
- void ConnectTrap(TrapReason reason) {
+ void ConnectTrap(wasm::TrapReason reason) {
if (traps_[reason] == nullptr) {
// Create trap code for the first time this trap is used.
return BuildTrapCode(reason);
@@ -215,8 +196,9 @@
builder_->AppendToPhi(traps_[reason], effects_[reason], builder_->Effect());
}
- void BuildTrapCode(TrapReason reason) {
- Node* exception = builder_->String(kTrapMessages[reason]);
+ void BuildTrapCode(wasm::TrapReason reason) {
+ Node* exception =
+ builder_->String(wasm::WasmOpcodes::TrapReasonName(reason));
Node* end;
Node** control_ptr = builder_->control_;
Node** effect_ptr = builder_->effect_;
@@ -265,7 +247,6 @@
}
};
-
WasmGraphBuilder::WasmGraphBuilder(Zone* zone, JSGraph* jsgraph,
wasm::FunctionSig* function_signature)
: zone_(zone),
@@ -351,8 +332,7 @@
Node* WasmGraphBuilder::Phi(wasm::LocalType type, unsigned count, Node** vals,
Node* control) {
DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
- Node** buf = Realloc(vals, count);
- buf = Realloc(buf, count + 1);
+ Node** buf = Realloc(vals, count, count + 1);
buf[count] = control;
return graph()->NewNode(jsgraph()->common()->Phi(type, count), count + 1,
buf);
@@ -362,8 +342,7 @@
Node* WasmGraphBuilder::EffectPhi(unsigned count, Node** effects,
Node* control) {
DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
- Node** buf = Realloc(effects, count);
- buf = Realloc(buf, count + 1);
+ Node** buf = Realloc(effects, count, count + 1);
buf[count] = control;
return graph()->NewNode(jsgraph()->common()->EffectPhi(count), count + 1,
buf);
@@ -394,43 +373,14 @@
case wasm::kExprI32Mul:
op = m->Int32Mul();
break;
- case wasm::kExprI32DivS: {
- trap_->ZeroCheck32(kTrapDivByZero, right);
- Node* before = *control_;
- Node* denom_is_m1;
- Node* denom_is_not_m1;
- Branch(graph()->NewNode(jsgraph()->machine()->Word32Equal(), right,
- jsgraph()->Int32Constant(-1)),
- &denom_is_m1, &denom_is_not_m1);
- *control_ = denom_is_m1;
- trap_->TrapIfEq32(kTrapDivUnrepresentable, left, kMinInt);
- if (*control_ != denom_is_m1) {
- *control_ = graph()->NewNode(jsgraph()->common()->Merge(2),
- denom_is_not_m1, *control_);
- } else {
- *control_ = before;
- }
- return graph()->NewNode(m->Int32Div(), left, right, *control_);
- }
+ case wasm::kExprI32DivS:
+ return BuildI32DivS(left, right);
case wasm::kExprI32DivU:
- op = m->Uint32Div();
- return graph()->NewNode(op, left, right,
- trap_->ZeroCheck32(kTrapDivByZero, right));
- case wasm::kExprI32RemS: {
- trap_->ZeroCheck32(kTrapRemByZero, right);
- Diamond d(graph(), jsgraph()->common(),
- graph()->NewNode(jsgraph()->machine()->Word32Equal(), right,
- jsgraph()->Int32Constant(-1)));
-
- Node* rem = graph()->NewNode(m->Int32Mod(), left, right, d.if_false);
-
- return d.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
- rem);
- }
+ return BuildI32DivU(left, right);
+ case wasm::kExprI32RemS:
+ return BuildI32RemS(left, right);
case wasm::kExprI32RemU:
- op = m->Uint32Mod();
- return graph()->NewNode(op, left, right,
- trap_->ZeroCheck32(kTrapRemByZero, right));
+ return BuildI32RemU(left, right);
case wasm::kExprI32And:
op = m->Word32And();
break;
@@ -442,13 +392,23 @@
break;
case wasm::kExprI32Shl:
op = m->Word32Shl();
+ right = MaskShiftCount32(right);
break;
case wasm::kExprI32ShrU:
op = m->Word32Shr();
+ right = MaskShiftCount32(right);
break;
case wasm::kExprI32ShrS:
op = m->Word32Sar();
+ right = MaskShiftCount32(right);
break;
+ case wasm::kExprI32Ror:
+ op = m->Word32Ror();
+ right = MaskShiftCount32(right);
+ break;
+ case wasm::kExprI32Rol:
+ right = MaskShiftCount32(right);
+ return BuildI32Rol(left, right);
case wasm::kExprI32Eq:
op = m->Word32Equal();
break;
@@ -485,76 +445,62 @@
case wasm::kExprI64And:
op = m->Word64And();
break;
-#if WASM_64
- // Opcodes only supported on 64-bit platforms.
- // TODO(titzer): query the machine operator builder here instead of #ifdef.
+ // todo(ahaas): I added a list of missing instructions here to make merging
+ // easier when I do them one by one.
+ // kExprI64Add:
case wasm::kExprI64Add:
op = m->Int64Add();
break;
+ // kExprI64Sub:
case wasm::kExprI64Sub:
op = m->Int64Sub();
break;
+ // kExprI64Mul:
case wasm::kExprI64Mul:
op = m->Int64Mul();
break;
- case wasm::kExprI64DivS: {
- trap_->ZeroCheck64(kTrapDivByZero, right);
- Node* before = *control_;
- Node* denom_is_m1;
- Node* denom_is_not_m1;
- Branch(graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
- jsgraph()->Int64Constant(-1)),
- &denom_is_m1, &denom_is_not_m1);
- *control_ = denom_is_m1;
- trap_->TrapIfEq64(kTrapDivUnrepresentable, left,
- std::numeric_limits<int64_t>::min());
- if (*control_ != denom_is_m1) {
- *control_ = graph()->NewNode(jsgraph()->common()->Merge(2),
- denom_is_not_m1, *control_);
- } else {
- *control_ = before;
- }
- return graph()->NewNode(m->Int64Div(), left, right, *control_);
- }
+ // kExprI64DivS:
+ case wasm::kExprI64DivS:
+ return BuildI64DivS(left, right);
+ // kExprI64DivU:
case wasm::kExprI64DivU:
- op = m->Uint64Div();
- return graph()->NewNode(op, left, right,
- trap_->ZeroCheck64(kTrapDivByZero, right));
- case wasm::kExprI64RemS: {
- trap_->ZeroCheck64(kTrapRemByZero, right);
- Diamond d(jsgraph()->graph(), jsgraph()->common(),
- graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
- jsgraph()->Int64Constant(-1)));
-
- Node* rem = graph()->NewNode(m->Int64Mod(), left, right, d.if_false);
-
- return d.Phi(MachineRepresentation::kWord64, jsgraph()->Int64Constant(0),
- rem);
- }
+ return BuildI64DivU(left, right);
+ // kExprI64RemS:
+ case wasm::kExprI64RemS:
+ return BuildI64RemS(left, right);
+ // kExprI64RemU:
case wasm::kExprI64RemU:
- op = m->Uint64Mod();
- return graph()->NewNode(op, left, right,
- trap_->ZeroCheck64(kTrapRemByZero, right));
+ return BuildI64RemU(left, right);
case wasm::kExprI64Ior:
op = m->Word64Or();
break;
+// kExprI64Xor:
case wasm::kExprI64Xor:
op = m->Word64Xor();
break;
+// kExprI64Shl:
case wasm::kExprI64Shl:
op = m->Word64Shl();
+ right = MaskShiftCount64(right);
break;
+ // kExprI64ShrU:
case wasm::kExprI64ShrU:
op = m->Word64Shr();
+ right = MaskShiftCount64(right);
break;
+ // kExprI64ShrS:
case wasm::kExprI64ShrS:
op = m->Word64Sar();
+ right = MaskShiftCount64(right);
break;
+ // kExprI64Eq:
case wasm::kExprI64Eq:
op = m->Word64Equal();
break;
+// kExprI64Ne:
case wasm::kExprI64Ne:
return Invert(Binop(wasm::kExprI64Eq, left, right));
+// kExprI64LtS:
case wasm::kExprI64LtS:
op = m->Int64LessThan();
break;
@@ -583,8 +529,12 @@
op = m->Uint64LessThanOrEqual();
std::swap(left, right);
break;
-#endif
-
+ case wasm::kExprI64Ror:
+ op = m->Word64Ror();
+ right = MaskShiftCount64(right);
+ break;
+ case wasm::kExprI64Rol:
+ return BuildI64Rol(left, right);
case wasm::kExprF32CopySign:
return BuildF32CopySign(left, right);
case wasm::kExprF64CopySign:
@@ -659,6 +609,15 @@
return BuildF32Max(left, right);
case wasm::kExprF64Max:
return BuildF64Max(left, right);
+ case wasm::kExprF64Pow: {
+ return BuildF64Pow(left, right);
+ }
+ case wasm::kExprF64Atan2: {
+ return BuildF64Atan2(left, right);
+ }
+ case wasm::kExprF64Mod: {
+ return BuildF64Mod(left, right);
+ }
default:
op = UnsupportedOpcode(opcode);
}
@@ -670,7 +629,7 @@
const Operator* op;
MachineOperatorBuilder* m = jsgraph()->machine();
switch (opcode) {
- case wasm::kExprBoolNot:
+ case wasm::kExprI32Eqz:
op = m->Word32Equal();
return graph()->NewNode(op, input, jsgraph()->Int32Constant(0));
case wasm::kExprF32Abs:
@@ -786,79 +745,62 @@
op = m->Float64RoundTiesEven().op();
break;
}
+ case wasm::kExprF64Acos: {
+ return BuildF64Acos(input);
+ }
+ case wasm::kExprF64Asin: {
+ return BuildF64Asin(input);
+ }
+ case wasm::kExprF64Atan: {
+ return BuildF64Atan(input);
+ }
+ case wasm::kExprF64Cos: {
+ return BuildF64Cos(input);
+ }
+ case wasm::kExprF64Sin: {
+ return BuildF64Sin(input);
+ }
+ case wasm::kExprF64Tan: {
+ return BuildF64Tan(input);
+ }
+ case wasm::kExprF64Exp: {
+ return BuildF64Exp(input);
+ }
+ case wasm::kExprF64Log: {
+ return BuildF64Log(input);
+ }
+ // kExprI32ConvertI64:
case wasm::kExprI32ConvertI64:
op = m->TruncateInt64ToInt32();
break;
-#if WASM_64
- // Opcodes only supported on 64-bit platforms.
- // TODO(titzer): query the machine operator builder here instead of #ifdef.
+ // kExprI64SConvertI32:
case wasm::kExprI64SConvertI32:
op = m->ChangeInt32ToInt64();
break;
+ // kExprI64UConvertI32:
case wasm::kExprI64UConvertI32:
op = m->ChangeUint32ToUint64();
break;
- case wasm::kExprF32SConvertI64:
- op = m->RoundInt64ToFloat32();
- break;
- case wasm::kExprF32UConvertI64:
- op = m->RoundUint64ToFloat32();
- break;
- case wasm::kExprF64SConvertI64:
- op = m->RoundInt64ToFloat64();
- break;
- case wasm::kExprF64UConvertI64:
- op = m->RoundUint64ToFloat64();
- break;
- case wasm::kExprI64SConvertF32: {
- Node* trunc = graph()->NewNode(m->TryTruncateFloat32ToInt64(), input);
- Node* result =
- graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
- Node* overflow =
- graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
- trap_->ZeroCheck64(kTrapFloatUnrepresentable, overflow);
- return result;
- }
- case wasm::kExprI64SConvertF64: {
- Node* trunc = graph()->NewNode(m->TryTruncateFloat64ToInt64(), input);
- Node* result =
- graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
- Node* overflow =
- graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
- trap_->ZeroCheck64(kTrapFloatUnrepresentable, overflow);
- return result;
- }
- case wasm::kExprI64UConvertF32: {
- Node* trunc = graph()->NewNode(m->TryTruncateFloat32ToUint64(), input);
- Node* result =
- graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
- Node* overflow =
- graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
- trap_->ZeroCheck64(kTrapFloatUnrepresentable, overflow);
- return result;
- }
- case wasm::kExprI64UConvertF64: {
- Node* trunc = graph()->NewNode(m->TryTruncateFloat64ToUint64(), input);
- Node* result =
- graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
- Node* overflow =
- graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
- trap_->ZeroCheck64(kTrapFloatUnrepresentable, overflow);
- return result;
- }
+ // kExprF64ReinterpretI64:
case wasm::kExprF64ReinterpretI64:
op = m->BitcastInt64ToFloat64();
break;
+ // kExprI64ReinterpretF64:
case wasm::kExprI64ReinterpretF64:
op = m->BitcastFloat64ToInt64();
break;
+ // kExprI64Clz:
case wasm::kExprI64Clz:
op = m->Word64Clz();
break;
+ // kExprI64Ctz:
case wasm::kExprI64Ctz: {
if (m->Word64Ctz().IsSupported()) {
op = m->Word64Ctz().op();
break;
+ } else if (m->Is32() && m->Word32Ctz().IsSupported()) {
+ op = m->Word64CtzPlaceholder();
+ break;
} else if (m->Word64ReverseBits().IsSupported()) {
Node* reversed = graph()->NewNode(m->Word64ReverseBits().op(), input);
Node* result = graph()->NewNode(m->Word64Clz(), reversed);
@@ -867,15 +809,64 @@
return BuildI64Ctz(input);
}
}
+ // kExprI64Popcnt:
case wasm::kExprI64Popcnt: {
if (m->Word64Popcnt().IsSupported()) {
op = m->Word64Popcnt().op();
- break;
+ } else if (m->Is32() && m->Word32Popcnt().IsSupported()) {
+ op = m->Word64PopcntPlaceholder();
} else {
return BuildI64Popcnt(input);
}
+ break;
}
-#endif
+ // kExprF32SConvertI64:
+ case wasm::kExprI64Eqz:
+ op = m->Word64Equal();
+ return graph()->NewNode(op, input, jsgraph()->Int64Constant(0));
+ case wasm::kExprF32SConvertI64:
+ if (m->Is32()) {
+ return BuildF32SConvertI64(input);
+ }
+ op = m->RoundInt64ToFloat32();
+ break;
+ // kExprF32UConvertI64:
+ case wasm::kExprF32UConvertI64:
+ if (m->Is32()) {
+ return BuildF32UConvertI64(input);
+ }
+ op = m->RoundUint64ToFloat32();
+ break;
+ // kExprF64SConvertI64:
+ case wasm::kExprF64SConvertI64:
+ if (m->Is32()) {
+ return BuildF64SConvertI64(input);
+ }
+ op = m->RoundInt64ToFloat64();
+ break;
+ // kExprF64UConvertI64:
+ case wasm::kExprF64UConvertI64:
+ if (m->Is32()) {
+ return BuildF64UConvertI64(input);
+ }
+ op = m->RoundUint64ToFloat64();
+ break;
+// kExprI64SConvertF32:
+ case wasm::kExprI64SConvertF32: {
+ return BuildI64SConvertF32(input);
+ }
+ // kExprI64SConvertF64:
+ case wasm::kExprI64SConvertF64: {
+ return BuildI64SConvertF64(input);
+ }
+ // kExprI64UConvertF32:
+ case wasm::kExprI64UConvertF32: {
+ return BuildI64UConvertF32(input);
+ }
+ // kExprI64UConvertF64:
+ case wasm::kExprI64UConvertF64: {
+ return BuildI64UConvertF64(input);
+ }
default:
op = UnsupportedOpcode(opcode);
}
@@ -937,8 +928,7 @@
count = 1;
}
- Node** buf = Realloc(vals, count);
- buf = Realloc(buf, count + 2);
+ Node** buf = Realloc(vals, count, count + 2);
buf[count] = *effect_;
buf[count + 1] = *control_;
Node* ret = graph()->NewNode(jsgraph()->common()->Return(), count + 2, vals);
@@ -956,6 +946,37 @@
return nullptr;
}
+Node* WasmGraphBuilder::MaskShiftCount32(Node* node) {
+ static const int32_t kMask32 = 0x1f;
+ if (!jsgraph()->machine()->Word32ShiftIsSafe()) {
+ // Shifts by constants are so common we pattern-match them here.
+ Int32Matcher match(node);
+ if (match.HasValue()) {
+ int32_t masked = (match.Value() & kMask32);
+ if (match.Value() != masked) node = jsgraph()->Int32Constant(masked);
+ } else {
+ node = graph()->NewNode(jsgraph()->machine()->Word32And(), node,
+ jsgraph()->Int32Constant(kMask32));
+ }
+ }
+ return node;
+}
+
+Node* WasmGraphBuilder::MaskShiftCount64(Node* node) {
+ static const int64_t kMask64 = 0x3f;
+ if (!jsgraph()->machine()->Word32ShiftIsSafe()) {
+ // Shifts by constants are so common we pattern-match them here.
+ Int64Matcher match(node);
+ if (match.HasValue()) {
+ int64_t masked = (match.Value() & kMask64);
+ if (match.Value() != masked) node = jsgraph()->Int64Constant(masked);
+ } else {
+ node = graph()->NewNode(jsgraph()->machine()->Word64And(), node,
+ jsgraph()->Int64Constant(kMask64));
+ }
+ }
+ return node;
+}
Node* WasmGraphBuilder::BuildF32Neg(Node* input) {
Node* result =
@@ -1115,6 +1136,13 @@
Node* WasmGraphBuilder::BuildI32SConvertF32(Node* input) {
MachineOperatorBuilder* m = jsgraph()->machine();
+ if (module_ && module_->asm_js()) {
+ // asm.js must use the wacky JS semantics.
+ input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input);
+ return graph()->NewNode(
+ m->TruncateFloat64ToInt32(TruncationMode::kJavaScript), input);
+ }
+
// Truncation of the input value is needed for the overflow check later.
Node* trunc = Unop(wasm::kExprF32Trunc, input);
Node* result = graph()->NewNode(m->TruncateFloat32ToInt32(), trunc);
@@ -1123,7 +1151,7 @@
// truncated input value, then there has been an overflow and we trap.
Node* check = Unop(wasm::kExprF32SConvertI32, result);
Node* overflow = Binop(wasm::kExprF32Ne, trunc, check);
- trap_->AddTrapIfTrue(kTrapFloatUnrepresentable, overflow);
+ trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow);
return result;
}
@@ -1131,7 +1159,8 @@
Node* WasmGraphBuilder::BuildI32SConvertF64(Node* input) {
MachineOperatorBuilder* m = jsgraph()->machine();
- if (module_ && module_->asm_js) {
+ if (module_ && module_->asm_js()) {
+ // asm.js must use the wacky JS semantics.
return graph()->NewNode(
m->TruncateFloat64ToInt32(TruncationMode::kJavaScript), input);
}
@@ -1143,7 +1172,7 @@
// truncated input value, then there has been an overflow and we trap.
Node* check = Unop(wasm::kExprF64SConvertI32, result);
Node* overflow = Binop(wasm::kExprF64Ne, trunc, check);
- trap_->AddTrapIfTrue(kTrapFloatUnrepresentable, overflow);
+ trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow);
return result;
}
@@ -1151,6 +1180,13 @@
Node* WasmGraphBuilder::BuildI32UConvertF32(Node* input) {
MachineOperatorBuilder* m = jsgraph()->machine();
+ if (module_ && module_->asm_js()) {
+ // asm.js must use the wacky JS semantics.
+ input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input);
+ return graph()->NewNode(
+ m->TruncateFloat64ToInt32(TruncationMode::kJavaScript), input);
+ }
+
// Truncation of the input value is needed for the overflow check later.
Node* trunc = Unop(wasm::kExprF32Trunc, input);
Node* result = graph()->NewNode(m->TruncateFloat32ToUint32(), trunc);
@@ -1159,7 +1195,7 @@
// truncated input value, then there has been an overflow and we trap.
Node* check = Unop(wasm::kExprF32UConvertI32, result);
Node* overflow = Binop(wasm::kExprF32Ne, trunc, check);
- trap_->AddTrapIfTrue(kTrapFloatUnrepresentable, overflow);
+ trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow);
return result;
}
@@ -1167,19 +1203,20 @@
Node* WasmGraphBuilder::BuildI32UConvertF64(Node* input) {
MachineOperatorBuilder* m = jsgraph()->machine();
- if (module_ && module_->asm_js) {
+ if (module_ && module_->asm_js()) {
+ // asm.js must use the wacky JS semantics.
return graph()->NewNode(
m->TruncateFloat64ToInt32(TruncationMode::kJavaScript), input);
}
// Truncation of the input value is needed for the overflow check later.
Node* trunc = Unop(wasm::kExprF64Trunc, input);
- Node* result = graph()->NewNode(m->ChangeFloat64ToUint32(), trunc);
+ Node* result = graph()->NewNode(m->TruncateFloat64ToUint32(), trunc);
// Convert the result back to f64. If we end up at a different value than the
// truncated input value, then there has been an overflow and we trap.
Node* check = Unop(wasm::kExprF64UConvertI32, result);
Node* overflow = Binop(wasm::kExprF64Ne, trunc, check);
- trap_->AddTrapIfTrue(kTrapFloatUnrepresentable, overflow);
+ trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow);
return result;
}
@@ -1363,89 +1400,557 @@
Node* WasmGraphBuilder::BuildF32Trunc(Node* input) {
MachineType type = MachineType::Float32();
ExternalReference ref =
- ExternalReference::f32_trunc_wrapper_function(jsgraph()->isolate());
- return BuildRoundingInstruction(input, ref, type);
+ ExternalReference::wasm_f32_trunc(jsgraph()->isolate());
+
+ return BuildCFuncInstruction(ref, type, input);
}
Node* WasmGraphBuilder::BuildF32Floor(Node* input) {
MachineType type = MachineType::Float32();
ExternalReference ref =
- ExternalReference::f32_floor_wrapper_function(jsgraph()->isolate());
- return BuildRoundingInstruction(input, ref, type);
+ ExternalReference::wasm_f32_floor(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, input);
}
Node* WasmGraphBuilder::BuildF32Ceil(Node* input) {
MachineType type = MachineType::Float32();
ExternalReference ref =
- ExternalReference::f32_ceil_wrapper_function(jsgraph()->isolate());
- return BuildRoundingInstruction(input, ref, type);
+ ExternalReference::wasm_f32_ceil(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, input);
}
Node* WasmGraphBuilder::BuildF32NearestInt(Node* input) {
MachineType type = MachineType::Float32();
ExternalReference ref =
- ExternalReference::f32_nearest_int_wrapper_function(jsgraph()->isolate());
- return BuildRoundingInstruction(input, ref, type);
+ ExternalReference::wasm_f32_nearest_int(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, input);
}
Node* WasmGraphBuilder::BuildF64Trunc(Node* input) {
MachineType type = MachineType::Float64();
ExternalReference ref =
- ExternalReference::f64_trunc_wrapper_function(jsgraph()->isolate());
- return BuildRoundingInstruction(input, ref, type);
+ ExternalReference::wasm_f64_trunc(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, input);
}
Node* WasmGraphBuilder::BuildF64Floor(Node* input) {
MachineType type = MachineType::Float64();
ExternalReference ref =
- ExternalReference::f64_floor_wrapper_function(jsgraph()->isolate());
- return BuildRoundingInstruction(input, ref, type);
+ ExternalReference::wasm_f64_floor(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, input);
}
Node* WasmGraphBuilder::BuildF64Ceil(Node* input) {
MachineType type = MachineType::Float64();
ExternalReference ref =
- ExternalReference::f64_ceil_wrapper_function(jsgraph()->isolate());
- return BuildRoundingInstruction(input, ref, type);
+ ExternalReference::wasm_f64_ceil(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, input);
}
Node* WasmGraphBuilder::BuildF64NearestInt(Node* input) {
MachineType type = MachineType::Float64();
ExternalReference ref =
- ExternalReference::f64_nearest_int_wrapper_function(jsgraph()->isolate());
- return BuildRoundingInstruction(input, ref, type);
+ ExternalReference::wasm_f64_nearest_int(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, input);
}
-Node* WasmGraphBuilder::BuildRoundingInstruction(Node* input,
- ExternalReference ref,
- MachineType type) {
- // We do truncation by calling a C function which calculates the truncation
- // for us. The input is passed to the C function as a double* to avoid double
- // parameters. For this we reserve a slot on the stack, store the parameter in
- // that slot, pass a pointer to the slot to the C function, and after calling
- // the C function we collect the return value from the stack slot.
+Node* WasmGraphBuilder::BuildF64Acos(Node* input) {
+ MachineType type = MachineType::Float64();
+ ExternalReference ref =
+ ExternalReference::f64_acos_wrapper_function(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, input);
+}
- Node* stack_slot_param =
+Node* WasmGraphBuilder::BuildF64Asin(Node* input) {
+ MachineType type = MachineType::Float64();
+ ExternalReference ref =
+ ExternalReference::f64_asin_wrapper_function(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, input);
+}
+
+Node* WasmGraphBuilder::BuildF64Atan(Node* input) {
+ MachineType type = MachineType::Float64();
+ ExternalReference ref =
+ ExternalReference::f64_atan_wrapper_function(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, input);
+}
+
+Node* WasmGraphBuilder::BuildF64Cos(Node* input) {
+ MachineType type = MachineType::Float64();
+ ExternalReference ref =
+ ExternalReference::f64_cos_wrapper_function(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, input);
+}
+
+Node* WasmGraphBuilder::BuildF64Sin(Node* input) {
+ MachineType type = MachineType::Float64();
+ ExternalReference ref =
+ ExternalReference::f64_sin_wrapper_function(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, input);
+}
+
+Node* WasmGraphBuilder::BuildF64Tan(Node* input) {
+ MachineType type = MachineType::Float64();
+ ExternalReference ref =
+ ExternalReference::f64_tan_wrapper_function(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, input);
+}
+
+Node* WasmGraphBuilder::BuildF64Exp(Node* input) {
+ MachineType type = MachineType::Float64();
+ ExternalReference ref =
+ ExternalReference::f64_exp_wrapper_function(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, input);
+}
+
+Node* WasmGraphBuilder::BuildF64Log(Node* input) {
+ MachineType type = MachineType::Float64();
+ ExternalReference ref =
+ ExternalReference::f64_log_wrapper_function(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, input);
+}
+
+Node* WasmGraphBuilder::BuildF64Atan2(Node* left, Node* right) {
+ MachineType type = MachineType::Float64();
+ ExternalReference ref =
+ ExternalReference::f64_atan2_wrapper_function(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, left, right);
+}
+
+Node* WasmGraphBuilder::BuildF64Pow(Node* left, Node* right) {
+ MachineType type = MachineType::Float64();
+ ExternalReference ref =
+ ExternalReference::f64_pow_wrapper_function(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, left, right);
+}
+
+Node* WasmGraphBuilder::BuildF64Mod(Node* left, Node* right) {
+ MachineType type = MachineType::Float64();
+ ExternalReference ref =
+ ExternalReference::f64_mod_wrapper_function(jsgraph()->isolate());
+ return BuildCFuncInstruction(ref, type, left, right);
+}
+
+Node* WasmGraphBuilder::BuildCFuncInstruction(ExternalReference ref,
+ MachineType type, Node* input0,
+ Node* input1) {
+ // We do truncation by calling a C function which calculates the result.
+ // The input is passed to the C function as a double*'s to avoid double
+ // parameters. For this we reserve slots on the stack, store the parameters
+ // in those slots, pass pointers to the slot to the C function,
+ // and after calling the C function we collect the return value from
+ // the stack slot.
+
+ Node* stack_slot_param0 =
graph()->NewNode(jsgraph()->machine()->StackSlot(type.representation()));
- const Operator* store_op = jsgraph()->machine()->Store(
+ const Operator* store_op0 = jsgraph()->machine()->Store(
StoreRepresentation(type.representation(), kNoWriteBarrier));
- *effect_ =
- graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
- input, *effect_, *control_);
+ *effect_ = graph()->NewNode(store_op0, stack_slot_param0,
+ jsgraph()->Int32Constant(0), input0, *effect_,
+ *control_);
- Signature<MachineType>::Builder sig_builder(jsgraph()->zone(), 0, 1);
- sig_builder.AddParam(MachineType::Pointer());
Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
+ Node** args = Buffer(5);
+ args[0] = function;
+ args[1] = stack_slot_param0;
+ int input_count = 1;
- Node* args[] = {function, stack_slot_param};
+ if (input1 != nullptr) {
+ Node* stack_slot_param1 = graph()->NewNode(
+ jsgraph()->machine()->StackSlot(type.representation()));
+ const Operator* store_op1 = jsgraph()->machine()->Store(
+ StoreRepresentation(type.representation(), kNoWriteBarrier));
+ *effect_ = graph()->NewNode(store_op1, stack_slot_param1,
+ jsgraph()->Int32Constant(0), input1, *effect_,
+ *control_);
+ args[2] = stack_slot_param1;
+ ++input_count;
+ }
+ Signature<MachineType>::Builder sig_builder(jsgraph()->zone(), 0,
+ input_count);
+ sig_builder.AddParam(MachineType::Pointer());
+ if (input1 != nullptr) {
+ sig_builder.AddParam(MachineType::Pointer());
+ }
BuildCCall(sig_builder.Build(), args);
const Operator* load_op = jsgraph()->machine()->Load(type);
Node* load =
- graph()->NewNode(load_op, stack_slot_param, jsgraph()->Int32Constant(0),
+ graph()->NewNode(load_op, stack_slot_param0, jsgraph()->Int32Constant(0),
+ *effect_, *control_);
+ *effect_ = load;
+ return load;
+}
+
+Node* WasmGraphBuilder::BuildF32SConvertI64(Node* input) {
+ // TODO(titzer/bradnelson): Check handlng of asm.js case.
+ return BuildIntToFloatConversionInstruction(
+ input, ExternalReference::wasm_int64_to_float32(jsgraph()->isolate()),
+ MachineRepresentation::kWord64, MachineType::Float32());
+}
+Node* WasmGraphBuilder::BuildF32UConvertI64(Node* input) {
+ // TODO(titzer/bradnelson): Check handlng of asm.js case.
+ return BuildIntToFloatConversionInstruction(
+ input, ExternalReference::wasm_uint64_to_float32(jsgraph()->isolate()),
+ MachineRepresentation::kWord64, MachineType::Float32());
+}
+Node* WasmGraphBuilder::BuildF64SConvertI64(Node* input) {
+ return BuildIntToFloatConversionInstruction(
+ input, ExternalReference::wasm_int64_to_float64(jsgraph()->isolate()),
+ MachineRepresentation::kWord64, MachineType::Float64());
+}
+Node* WasmGraphBuilder::BuildF64UConvertI64(Node* input) {
+ return BuildIntToFloatConversionInstruction(
+ input, ExternalReference::wasm_uint64_to_float64(jsgraph()->isolate()),
+ MachineRepresentation::kWord64, MachineType::Float64());
+}
+
+Node* WasmGraphBuilder::BuildIntToFloatConversionInstruction(
+ Node* input, ExternalReference ref,
+ MachineRepresentation parameter_representation,
+ const MachineType result_type) {
+ Node* stack_slot_param = graph()->NewNode(
+ jsgraph()->machine()->StackSlot(parameter_representation));
+ Node* stack_slot_result = graph()->NewNode(
+ jsgraph()->machine()->StackSlot(result_type.representation()));
+ const Operator* store_op = jsgraph()->machine()->Store(
+ StoreRepresentation(parameter_representation, kNoWriteBarrier));
+ *effect_ =
+ graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
+ input, *effect_, *control_);
+ MachineSignature::Builder sig_builder(jsgraph()->zone(), 0, 2);
+ sig_builder.AddParam(MachineType::Pointer());
+ sig_builder.AddParam(MachineType::Pointer());
+ Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
+ Node* args[] = {function, stack_slot_param, stack_slot_result};
+ BuildCCall(sig_builder.Build(), args);
+ const Operator* load_op = jsgraph()->machine()->Load(result_type);
+ Node* load =
+ graph()->NewNode(load_op, stack_slot_result, jsgraph()->Int32Constant(0),
+ *effect_, *control_);
+ *effect_ = load;
+ return load;
+}
+
+Node* WasmGraphBuilder::BuildI64SConvertF32(Node* input) {
+ if (jsgraph()->machine()->Is32()) {
+ return BuildFloatToIntConversionInstruction(
+ input, ExternalReference::wasm_float32_to_int64(jsgraph()->isolate()),
+ MachineRepresentation::kFloat32, MachineType::Int64());
+ } else {
+ Node* trunc = graph()->NewNode(
+ jsgraph()->machine()->TryTruncateFloat32ToInt64(), input);
+ Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
+ Node* overflow =
+ graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
+ trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow);
+ return result;
+ }
+}
+
+Node* WasmGraphBuilder::BuildI64UConvertF32(Node* input) {
+ if (jsgraph()->machine()->Is32()) {
+ return BuildFloatToIntConversionInstruction(
+ input, ExternalReference::wasm_float32_to_uint64(jsgraph()->isolate()),
+ MachineRepresentation::kFloat32, MachineType::Int64());
+ } else {
+ Node* trunc = graph()->NewNode(
+ jsgraph()->machine()->TryTruncateFloat32ToUint64(), input);
+ Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
+ Node* overflow =
+ graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
+ trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow);
+ return result;
+ }
+}
+
+Node* WasmGraphBuilder::BuildI64SConvertF64(Node* input) {
+ if (jsgraph()->machine()->Is32()) {
+ return BuildFloatToIntConversionInstruction(
+ input, ExternalReference::wasm_float64_to_int64(jsgraph()->isolate()),
+ MachineRepresentation::kFloat64, MachineType::Int64());
+ } else {
+ Node* trunc = graph()->NewNode(
+ jsgraph()->machine()->TryTruncateFloat64ToInt64(), input);
+ Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
+ Node* overflow =
+ graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
+ trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow);
+ return result;
+ }
+}
+
+Node* WasmGraphBuilder::BuildI64UConvertF64(Node* input) {
+ if (jsgraph()->machine()->Is32()) {
+ return BuildFloatToIntConversionInstruction(
+ input, ExternalReference::wasm_float64_to_uint64(jsgraph()->isolate()),
+ MachineRepresentation::kFloat64, MachineType::Int64());
+ } else {
+ Node* trunc = graph()->NewNode(
+ jsgraph()->machine()->TryTruncateFloat64ToUint64(), input);
+ Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
+ Node* overflow =
+ graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
+ trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow);
+ return result;
+ }
+}
+
+Node* WasmGraphBuilder::BuildFloatToIntConversionInstruction(
+ Node* input, ExternalReference ref,
+ MachineRepresentation parameter_representation,
+ const MachineType result_type) {
+ Node* stack_slot_param = graph()->NewNode(
+ jsgraph()->machine()->StackSlot(parameter_representation));
+ Node* stack_slot_result = graph()->NewNode(
+ jsgraph()->machine()->StackSlot(result_type.representation()));
+ const Operator* store_op = jsgraph()->machine()->Store(
+ StoreRepresentation(parameter_representation, kNoWriteBarrier));
+ *effect_ =
+ graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
+ input, *effect_, *control_);
+ MachineSignature::Builder sig_builder(jsgraph()->zone(), 1, 2);
+ sig_builder.AddReturn(MachineType::Int32());
+ sig_builder.AddParam(MachineType::Pointer());
+ sig_builder.AddParam(MachineType::Pointer());
+ Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
+ Node* args[] = {function, stack_slot_param, stack_slot_result};
+ trap_->ZeroCheck32(wasm::kTrapFloatUnrepresentable,
+ BuildCCall(sig_builder.Build(), args));
+ const Operator* load_op = jsgraph()->machine()->Load(result_type);
+ Node* load =
+ graph()->NewNode(load_op, stack_slot_result, jsgraph()->Int32Constant(0),
+ *effect_, *control_);
+ *effect_ = load;
+ return load;
+}
+
+Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right) {
+ MachineOperatorBuilder* m = jsgraph()->machine();
+ if (module_ && module_->asm_js()) {
+ // asm.js semantics return 0 on divide or mod by zero.
+ if (m->Int32DivIsSafe()) {
+ // The hardware instruction does the right thing (e.g. arm).
+ return graph()->NewNode(m->Int32Div(), left, right, graph()->start());
+ }
+
+ // Check denominator for zero.
+ Diamond z(
+ graph(), jsgraph()->common(),
+ graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
+ BranchHint::kFalse);
+
+ // Check numerator for -1. (avoid minint / -1 case).
+ Diamond n(
+ graph(), jsgraph()->common(),
+ graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
+ BranchHint::kFalse);
+
+ Node* div = graph()->NewNode(m->Int32Div(), left, right, z.if_false);
+ Node* neg =
+ graph()->NewNode(m->Int32Sub(), jsgraph()->Int32Constant(0), left);
+
+ return n.Phi(MachineRepresentation::kWord32, neg,
+ z.Phi(MachineRepresentation::kWord32,
+ jsgraph()->Int32Constant(0), div));
+ }
+
+ trap_->ZeroCheck32(wasm::kTrapDivByZero, right);
+ Node* before = *control_;
+ Node* denom_is_m1;
+ Node* denom_is_not_m1;
+ Branch(
+ graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
+ &denom_is_m1, &denom_is_not_m1);
+ *control_ = denom_is_m1;
+ trap_->TrapIfEq32(wasm::kTrapDivUnrepresentable, left, kMinInt);
+ if (*control_ != denom_is_m1) {
+ *control_ = graph()->NewNode(jsgraph()->common()->Merge(2), denom_is_not_m1,
+ *control_);
+ } else {
+ *control_ = before;
+ }
+ return graph()->NewNode(m->Int32Div(), left, right, *control_);
+}
+
+Node* WasmGraphBuilder::BuildI32RemS(Node* left, Node* right) {
+ MachineOperatorBuilder* m = jsgraph()->machine();
+ if (module_ && module_->asm_js()) {
+ // asm.js semantics return 0 on divide or mod by zero.
+ // Explicit check for x % 0.
+ Diamond z(
+ graph(), jsgraph()->common(),
+ graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
+ BranchHint::kFalse);
+
+ // Explicit check for x % -1.
+ Diamond d(
+ graph(), jsgraph()->common(),
+ graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
+ BranchHint::kFalse);
+ d.Chain(z.if_false);
+
+ return z.Phi(
+ MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
+ d.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
+ graph()->NewNode(m->Int32Mod(), left, right, d.if_false)));
+ }
+
+ trap_->ZeroCheck32(wasm::kTrapRemByZero, right);
+
+ Diamond d(
+ graph(), jsgraph()->common(),
+ graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
+ BranchHint::kFalse);
+ d.Chain(*control_);
+
+ return d.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
+ graph()->NewNode(m->Int32Mod(), left, right, d.if_false));
+}
+
+Node* WasmGraphBuilder::BuildI32DivU(Node* left, Node* right) {
+ MachineOperatorBuilder* m = jsgraph()->machine();
+ if (module_ && module_->asm_js()) {
+ // asm.js semantics return 0 on divide or mod by zero.
+ if (m->Uint32DivIsSafe()) {
+ // The hardware instruction does the right thing (e.g. arm).
+ return graph()->NewNode(m->Uint32Div(), left, right, graph()->start());
+ }
+
+ // Explicit check for x % 0.
+ Diamond z(
+ graph(), jsgraph()->common(),
+ graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
+ BranchHint::kFalse);
+
+ return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
+ graph()->NewNode(jsgraph()->machine()->Uint32Div(), left,
+ right, z.if_false));
+ }
+ return graph()->NewNode(m->Uint32Div(), left, right,
+ trap_->ZeroCheck32(wasm::kTrapDivByZero, right));
+}
+
+Node* WasmGraphBuilder::BuildI32RemU(Node* left, Node* right) {
+ MachineOperatorBuilder* m = jsgraph()->machine();
+ if (module_ && module_->asm_js()) {
+ // asm.js semantics return 0 on divide or mod by zero.
+ // Explicit check for x % 0.
+ Diamond z(
+ graph(), jsgraph()->common(),
+ graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
+ BranchHint::kFalse);
+
+ Node* rem = graph()->NewNode(jsgraph()->machine()->Uint32Mod(), left, right,
+ z.if_false);
+ return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
+ rem);
+ }
+
+ return graph()->NewNode(m->Uint32Mod(), left, right,
+ trap_->ZeroCheck32(wasm::kTrapRemByZero, right));
+}
+
+Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right) {
+ if (jsgraph()->machine()->Is32()) {
+ return BuildDiv64Call(
+ left, right, ExternalReference::wasm_int64_div(jsgraph()->isolate()),
+ MachineType::Int64(), wasm::kTrapDivByZero);
+ }
+ trap_->ZeroCheck64(wasm::kTrapDivByZero, right);
+ Node* before = *control_;
+ Node* denom_is_m1;
+ Node* denom_is_not_m1;
+ Branch(graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
+ jsgraph()->Int64Constant(-1)),
+ &denom_is_m1, &denom_is_not_m1);
+ *control_ = denom_is_m1;
+ trap_->TrapIfEq64(wasm::kTrapDivUnrepresentable, left,
+ std::numeric_limits<int64_t>::min());
+ if (*control_ != denom_is_m1) {
+ *control_ = graph()->NewNode(jsgraph()->common()->Merge(2), denom_is_not_m1,
+ *control_);
+ } else {
+ *control_ = before;
+ }
+ return graph()->NewNode(jsgraph()->machine()->Int64Div(), left, right,
+ *control_);
+}
+
+Node* WasmGraphBuilder::BuildI64RemS(Node* left, Node* right) {
+ if (jsgraph()->machine()->Is32()) {
+ return BuildDiv64Call(
+ left, right, ExternalReference::wasm_int64_mod(jsgraph()->isolate()),
+ MachineType::Int64(), wasm::kTrapRemByZero);
+ }
+ trap_->ZeroCheck64(wasm::kTrapRemByZero, right);
+ Diamond d(jsgraph()->graph(), jsgraph()->common(),
+ graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
+ jsgraph()->Int64Constant(-1)));
+
+ Node* rem = graph()->NewNode(jsgraph()->machine()->Int64Mod(), left, right,
+ d.if_false);
+
+ return d.Phi(MachineRepresentation::kWord64, jsgraph()->Int64Constant(0),
+ rem);
+}
+
+Node* WasmGraphBuilder::BuildI64DivU(Node* left, Node* right) {
+ if (jsgraph()->machine()->Is32()) {
+ return BuildDiv64Call(
+ left, right, ExternalReference::wasm_uint64_div(jsgraph()->isolate()),
+ MachineType::Int64(), wasm::kTrapDivByZero);
+ }
+ return graph()->NewNode(jsgraph()->machine()->Uint64Div(), left, right,
+ trap_->ZeroCheck64(wasm::kTrapDivByZero, right));
+}
+Node* WasmGraphBuilder::BuildI64RemU(Node* left, Node* right) {
+ if (jsgraph()->machine()->Is32()) {
+ return BuildDiv64Call(
+ left, right, ExternalReference::wasm_uint64_mod(jsgraph()->isolate()),
+ MachineType::Int64(), wasm::kTrapRemByZero);
+ }
+ return graph()->NewNode(jsgraph()->machine()->Uint64Mod(), left, right,
+ trap_->ZeroCheck64(wasm::kTrapRemByZero, right));
+}
+
+Node* WasmGraphBuilder::BuildDiv64Call(Node* left, Node* right,
+ ExternalReference ref,
+ MachineType result_type, int trap_zero) {
+ Node* stack_slot_dst = graph()->NewNode(
+ jsgraph()->machine()->StackSlot(MachineRepresentation::kWord64));
+ Node* stack_slot_src = graph()->NewNode(
+ jsgraph()->machine()->StackSlot(MachineRepresentation::kWord64));
+
+ const Operator* store_op = jsgraph()->machine()->Store(
+ StoreRepresentation(MachineRepresentation::kWord64, kNoWriteBarrier));
+ *effect_ =
+ graph()->NewNode(store_op, stack_slot_dst, jsgraph()->Int32Constant(0),
+ left, *effect_, *control_);
+ *effect_ =
+ graph()->NewNode(store_op, stack_slot_src, jsgraph()->Int32Constant(0),
+ right, *effect_, *control_);
+
+ MachineSignature::Builder sig_builder(jsgraph()->zone(), 1, 2);
+ sig_builder.AddReturn(MachineType::Int32());
+ sig_builder.AddParam(MachineType::Pointer());
+ sig_builder.AddParam(MachineType::Pointer());
+
+ Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
+ Node* args[] = {function, stack_slot_dst, stack_slot_src};
+
+ Node* call = BuildCCall(sig_builder.Build(), args);
+
+ // TODO(wasm): This can get simpler if we have a specialized runtime call to
+ // throw WASM exceptions by trap code instead of by string.
+ trap_->ZeroCheck32(static_cast<wasm::TrapReason>(trap_zero), call);
+ trap_->TrapIfEq32(wasm::kTrapDivUnrepresentable, call, -1);
+ const Operator* load_op = jsgraph()->machine()->Load(result_type);
+ Node* load =
+ graph()->NewNode(load_op, stack_slot_dst, jsgraph()->Int32Constant(0),
*effect_, *control_);
*effect_ = load;
return load;
@@ -1457,7 +1962,7 @@
const size_t count = 1 + params + extra;
// Reallocate the buffer to make space for extra inputs.
- args = Realloc(args, count);
+ args = Realloc(args, 1 + params, count);
// Add effect and control inputs.
args[params + 1] = *effect_;
@@ -1478,7 +1983,7 @@
const size_t count = 1 + params + extra;
// Reallocate the buffer to make space for extra inputs.
- args = Realloc(args, count);
+ args = Realloc(args, 1 + params, count);
// Add effect and control inputs.
args[params + 1] = *effect_;
@@ -1493,7 +1998,6 @@
return call;
}
-
Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args) {
DCHECK_NULL(args[0]);
@@ -1529,10 +2033,10 @@
// Bounds check against the table size.
Node* size = Int32Constant(static_cast<int>(table_size));
Node* in_bounds = graph()->NewNode(machine->Uint32LessThan(), key, size);
- trap_->AddTrapIfFalse(kTrapFuncInvalid, in_bounds);
+ trap_->AddTrapIfFalse(wasm::kTrapFuncInvalid, in_bounds);
} else {
// No function table. Generate a trap and return a constant.
- trap_->AddTrapIfFalse(kTrapFuncInvalid, Int32Constant(0));
+ trap_->AddTrapIfFalse(wasm::kTrapFuncInvalid, Int32Constant(0));
return trap_->GetTrapValue(module_->GetSignature(index));
}
Node* table = FunctionTable();
@@ -1552,7 +2056,7 @@
*effect_, *control_);
Node* sig_match = graph()->NewNode(machine->WordEqual(), load_sig,
jsgraph()->SmiConstant(index));
- trap_->AddTrapIfFalse(kTrapFuncSigMismatch, sig_match);
+ trap_->AddTrapIfFalse(wasm::kTrapFuncSigMismatch, sig_match);
}
// Load code object from the table.
@@ -1640,9 +2144,34 @@
return num;
}
+Node* WasmGraphBuilder::BuildI32Rol(Node* left, Node* right) {
+ // Implement Rol by Ror since TurboFan does not have Rol opcode.
+ // TODO(weiliang): support Word32Rol opcode in TurboFan.
+ Int32Matcher m(right);
+ if (m.HasValue()) {
+ return Binop(wasm::kExprI32Ror, left,
+ jsgraph()->Int32Constant(32 - m.Value()));
+ } else {
+ return Binop(wasm::kExprI32Ror, left,
+ Binop(wasm::kExprI32Sub, jsgraph()->Int32Constant(32), right));
+ }
+}
+
+Node* WasmGraphBuilder::BuildI64Rol(Node* left, Node* right) {
+ // Implement Rol by Ror since TurboFan does not have Rol opcode.
+ // TODO(weiliang): support Word64Rol opcode in TurboFan.
+ Int64Matcher m(right);
+ if (m.HasValue()) {
+ return Binop(wasm::kExprI64Ror, left,
+ jsgraph()->Int64Constant(64 - m.Value()));
+ } else {
+ return Binop(wasm::kExprI64Ror, left,
+ Binop(wasm::kExprI64Sub, jsgraph()->Int64Constant(64), right));
+ }
+}
Node* WasmGraphBuilder::Invert(Node* node) {
- return Unop(wasm::kExprBoolNot, node);
+ return Unop(wasm::kExprI32Eqz, node);
}
@@ -1653,19 +2182,22 @@
Node** args = Buffer(count);
// Build the start and the JS parameter nodes.
- Node* start = Start(params + 3);
+ Node* start = Start(params + 5);
*control_ = start;
*effect_ = start;
- // JS context is the last parameter.
+ // Create the context parameter
Node* context = graph()->NewNode(
- jsgraph()->common()->Parameter(params + 1, "context"), start);
+ jsgraph()->common()->Parameter(
+ Linkage::GetJSCallContextParamIndex(params + 1), "%context"),
+ graph()->start());
int pos = 0;
args[pos++] = Constant(wasm_code);
// Convert JS parameters to WASM numbers.
for (int i = 0; i < params; i++) {
- Node* param = graph()->NewNode(jsgraph()->common()->Parameter(i), start);
+ Node* param =
+ graph()->NewNode(jsgraph()->common()->Parameter(i + 1), start);
args[pos++] = FromJS(param, context, sig->GetParam(i));
}
@@ -1800,7 +2332,7 @@
MachineType mem_type = module_->GetGlobalType(index);
Node* addr = jsgraph()->IntPtrConstant(
reinterpret_cast<uintptr_t>(module_->instance->globals_start +
- module_->module->globals->at(index).offset));
+ module_->module->globals[index].offset));
const Operator* op = jsgraph()->machine()->Load(mem_type);
Node* node = graph()->NewNode(op, addr, jsgraph()->Int32Constant(0), *effect_,
*control_);
@@ -1814,7 +2346,7 @@
MachineType mem_type = module_->GetGlobalType(index);
Node* addr = jsgraph()->IntPtrConstant(
reinterpret_cast<uintptr_t>(module_->instance->globals_start +
- module_->module->globals->at(index).offset));
+ module_->module->globals[index].offset));
const Operator* op = jsgraph()->machine()->Store(
StoreRepresentation(mem_type.representation(), kNoWriteBarrier));
Node* node = graph()->NewNode(op, addr, jsgraph()->Int32Constant(0), val,
@@ -1843,7 +2375,7 @@
jsgraph()->Int32Constant(static_cast<uint32_t>(limit)));
}
- trap_->AddTrapIfFalse(kTrapMemOutOfBounds, cond);
+ trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond);
}
@@ -1851,7 +2383,7 @@
Node* index, uint32_t offset) {
Node* load;
- if (module_ && module_->asm_js) {
+ if (module_ && module_->asm_js()) {
// asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish).
DCHECK_EQ(0, offset);
const Operator* op = jsgraph()->machine()->CheckedLoad(memtype);
@@ -1886,7 +2418,7 @@
Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
uint32_t offset, Node* val) {
Node* store;
- if (module_ && module_->asm_js) {
+ if (module_ && module_->asm_js()) {
// asm.js semantics use CheckedStore (i.e. ignore OOB writes).
DCHECK_EQ(0, offset);
const Operator* op =
@@ -1920,7 +2452,7 @@
Graph* WasmGraphBuilder::graph() { return jsgraph()->graph(); }
void WasmGraphBuilder::Int64LoweringForTesting() {
- if (kPointerSize == 4) {
+ if (jsgraph()->machine()->Is32()) {
Int64Lowering r(jsgraph()->graph(), jsgraph()->machine(),
jsgraph()->common(), jsgraph()->zone(),
function_signature_);
@@ -1931,12 +2463,13 @@
static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
CompilationInfo* info,
const char* message, uint32_t index,
- const char* func_name) {
+ wasm::WasmName func_name) {
Isolate* isolate = info->isolate();
if (isolate->logger()->is_logging_code_events() ||
isolate->cpu_profiler()->is_profiling()) {
ScopedVector<char> buffer(128);
- SNPrintF(buffer, "%s#%d:%s", message, index, func_name);
+ SNPrintF(buffer, "%s#%d:%.*s", message, index, func_name.length,
+ func_name.name);
Handle<String> name_str =
isolate->factory()->NewStringFromAsciiChecked(buffer.start());
Handle<String> script_str =
@@ -1944,15 +2477,15 @@
Handle<Code> code = info->code();
Handle<SharedFunctionInfo> shared =
isolate->factory()->NewSharedFunctionInfo(name_str, code, false);
- PROFILE(isolate,
- CodeCreateEvent(tag, *code, *shared, info, *script_str, 0, 0));
+ PROFILE(isolate, CodeCreateEvent(tag, AbstractCode::cast(*code), *shared,
+ info, *script_str, 0, 0));
}
}
Handle<JSFunction> CompileJSToWasmWrapper(
Isolate* isolate, wasm::ModuleEnv* module, Handle<String> name,
Handle<Code> wasm_code, Handle<JSObject> module_object, uint32_t index) {
- wasm::WasmFunction* func = &module->module->functions->at(index);
+ wasm::WasmFunction* func = &module->module->functions[index];
//----------------------------------------------------------------------------
// Create the JSFunction object.
@@ -1961,7 +2494,7 @@
isolate->factory()->NewSharedFunctionInfo(name, wasm_code, false);
int params = static_cast<int>(func->sig->parameter_count());
shared->set_length(params);
- shared->set_internal_formal_parameter_count(1 + params);
+ shared->set_internal_formal_parameter_count(params);
Handle<JSFunction> function = isolate->factory()->NewFunction(
isolate->wasm_function_map(), name, MaybeHandle<Code>());
function->SetInternalField(0, *module_object);
@@ -1970,7 +2503,7 @@
//----------------------------------------------------------------------------
// Create the Graph
//----------------------------------------------------------------------------
- Zone zone;
+ Zone zone(isolate->allocator());
Graph graph(&zone);
CommonOperatorBuilder common(&zone);
JSOperatorBuilder javascript(&zone);
@@ -2015,8 +2548,7 @@
module->GetFunctionSignature(index)->parameter_count());
CallDescriptor* incoming = Linkage::GetJSCallDescriptor(
&zone, false, params + 1, CallDescriptor::kNoFlags);
- // TODO(titzer): this is technically a WASM wrapper, not a wasm function.
- Code::Flags flags = Code::ComputeFlags(Code::WASM_FUNCTION);
+ Code::Flags flags = Code::ComputeFlags(Code::JS_TO_WASM_FUNCTION);
bool debugging =
#if DEBUG
true;
@@ -2036,12 +2568,19 @@
CompilationInfo info(func_name, isolate, &zone, flags);
Handle<Code> code =
Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr);
+#ifdef ENABLE_DISASSEMBLER
+ if (FLAG_print_opt_code && !code.is_null()) {
+ OFStream os(stdout);
+ code->Disassemble(buffer.start(), os);
+ }
+#endif
if (debugging) {
buffer.Dispose();
}
- RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, "js-to-wasm", index,
- module->module->GetName(func->name_offset));
+ RecordFunctionCompilation(
+ Logger::FUNCTION_TAG, &info, "js-to-wasm", index,
+ module->module->GetName(func->name_offset, func->name_length));
// Set the JSFunction's machine code.
function->set_code(*code);
}
@@ -2050,11 +2589,13 @@
Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, wasm::ModuleEnv* module,
Handle<JSFunction> function,
- wasm::FunctionSig* sig, const char* name) {
+ wasm::FunctionSig* sig,
+ wasm::WasmName module_name,
+ wasm::WasmName function_name) {
//----------------------------------------------------------------------------
// Create the Graph
//----------------------------------------------------------------------------
- Zone zone;
+ Zone zone(isolate->allocator());
Graph graph(&zone);
CommonOperatorBuilder common(&zone);
JSOperatorBuilder javascript(&zone);
@@ -2095,8 +2636,7 @@
// Schedule and compile to machine code.
CallDescriptor* incoming =
wasm::ModuleEnv::GetWasmCallDescriptor(&zone, sig);
- // TODO(titzer): this is technically a WASM wrapper, not a wasm function.
- Code::Flags flags = Code::ComputeFlags(Code::WASM_FUNCTION);
+ Code::Flags flags = Code::ComputeFlags(Code::WASM_TO_JS_FUNCTION);
bool debugging =
#if DEBUG
true;
@@ -2114,12 +2654,18 @@
CompilationInfo info(func_name, isolate, &zone, flags);
code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr);
+#ifdef ENABLE_DISASSEMBLER
+ if (FLAG_print_opt_code && !code.is_null()) {
+ OFStream os(stdout);
+ code->Disassemble(buffer.start(), os);
+ }
+#endif
if (debugging) {
buffer.Dispose();
}
RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, "wasm-to-js", 0,
- name);
+ module_name);
}
return code;
}
@@ -2129,24 +2675,21 @@
Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
wasm::ModuleEnv* module_env,
const wasm::WasmFunction& function) {
- if (FLAG_trace_wasm_compiler || FLAG_trace_wasm_decode_time) {
+ if (FLAG_trace_wasm_compiler) {
OFStream os(stdout);
os << "Compiling WASM function "
<< wasm::WasmFunctionName(&function, module_env) << std::endl;
os << std::endl;
}
- // Initialize the function environment for decoding.
- wasm::FunctionEnv env;
- env.module = module_env;
- env.sig = function.sig;
- env.local_i32_count = function.local_i32_count;
- env.local_i64_count = function.local_i64_count;
- env.local_f32_count = function.local_f32_count;
- env.local_f64_count = function.local_f64_count;
- env.SumLocals();
+
+ double decode_ms = 0;
+ base::ElapsedTimer decode_timer;
+ if (FLAG_trace_wasm_decode_time) {
+ decode_timer.Start();
+ }
// Create a TF graph during decoding.
- Zone zone;
+ Zone zone(isolate->allocator());
Graph graph(&zone);
CommonOperatorBuilder common(&zone);
MachineOperatorBuilder machine(
@@ -2154,11 +2697,12 @@
InstructionSelector::SupportedMachineOperatorFlags());
JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
WasmGraphBuilder builder(&zone, &jsgraph, function.sig);
- wasm::TreeResult result = wasm::BuildTFGraph(
- &builder, &env, // --
- module_env->module->module_start, // --
- module_env->module->module_start + function.code_start_offset, // --
- module_env->module->module_start + function.code_end_offset); // --
+ wasm::FunctionBody body = {
+ module_env, function.sig, module_env->module->module_start,
+ module_env->module->module_start + function.code_start_offset,
+ module_env->module->module_start + function.code_end_offset};
+ wasm::TreeResult result =
+ wasm::BuildTFGraph(isolate->allocator(), &builder, body);
if (result.failed()) {
if (FLAG_trace_wasm_compiler) {
@@ -2167,17 +2711,31 @@
}
// Add the function as another context for the exception
ScopedVector<char> buffer(128);
- SNPrintF(buffer, "Compiling WASM function #%d:%s failed:",
- function.func_index,
- module_env->module->GetName(function.name_offset));
+ wasm::WasmName name =
+ module_env->module->GetName(function.name_offset, function.name_length);
+ SNPrintF(buffer, "Compiling WASM function #%d:%.*s failed:",
+ function.func_index, name.length, name.name);
thrower.Failed(buffer.start(), result);
return Handle<Code>::null();
}
+ int index = static_cast<int>(function.func_index);
+ if (index >= FLAG_trace_wasm_ast_start && index < FLAG_trace_wasm_ast_end) {
+ PrintAst(isolate->allocator(), body);
+ }
+
+ if (FLAG_trace_wasm_decode_time) {
+ decode_ms = decode_timer.Elapsed().InMillisecondsF();
+ }
+
+ base::ElapsedTimer compile_timer;
+ if (FLAG_trace_wasm_decode_time) {
+ compile_timer.Start();
+ }
// Run the compiler pipeline to generate machine code.
CallDescriptor* descriptor =
wasm::ModuleEnv::GetWasmCallDescriptor(&zone, function.sig);
- if (kPointerSize == 4) {
+ if (machine.Is32()) {
descriptor = module_env->GetI32WasmCallDescriptor(&zone, descriptor);
}
Code::Flags flags = Code::ComputeFlags(Code::WASM_FUNCTION);
@@ -2192,8 +2750,10 @@
Vector<char> buffer;
if (debugging) {
buffer = Vector<char>::New(128);
- SNPrintF(buffer, "WASM_function_#%d:%s", function.func_index,
- module_env->module->GetName(function.name_offset));
+ wasm::WasmName name =
+ module_env->module->GetName(function.name_offset, function.name_length);
+ SNPrintF(buffer, "WASM_function_#%d:%.*s", function.func_index, name.length,
+ name.name);
func_name = buffer.start();
}
CompilationInfo info(func_name, isolate, &zone, flags);
@@ -2204,11 +2764,20 @@
buffer.Dispose();
}
if (!code.is_null()) {
- RecordFunctionCompilation(
- Logger::FUNCTION_TAG, &info, "WASM_function", function.func_index,
- module_env->module->GetName(function.name_offset));
+ RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, "WASM_function",
+ function.func_index,
+ module_env->module->GetName(
+ function.name_offset, function.name_length));
}
+ if (FLAG_trace_wasm_decode_time) {
+ double compile_ms = compile_timer.Elapsed().InMillisecondsF();
+ PrintF(
+ "wasm-compile ok: %d bytes, %0.3f ms decode, %d nodes, %0.3f ms "
+ "compile\n",
+ static_cast<int>(function.code_end_offset - function.code_start_offset),
+ decode_ms, static_cast<int>(graph.NodeCount()), compile_ms);
+ }
return code;
}