Merge V8 5.2.361.47 DO NOT MERGE
https://chromium.googlesource.com/v8/v8/+/5.2.361.47
FPIIM-449
Change-Id: Ibec421b85a9b88cb3a432ada642e469fe7e78346
(cherry picked from commit bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8)
diff --git a/src/compiler/wasm-compiler.cc b/src/compiler/wasm-compiler.cc
index 93d5a08..619e639 100644
--- a/src/compiler/wasm-compiler.cc
+++ b/src/compiler/wasm-compiler.cc
@@ -10,11 +10,10 @@
#include "src/base/platform/platform.h"
#include "src/compiler/access-builder.h"
-#include "src/compiler/change-lowering.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/diamond.h"
-#include "src/compiler/graph.h"
#include "src/compiler/graph-visualizer.h"
+#include "src/compiler/graph.h"
#include "src/compiler/instruction-selector.h"
#include "src/compiler/int64-lowering.h"
#include "src/compiler/js-generic-lowering.h"
@@ -24,10 +23,8 @@
#include "src/compiler/machine-operator.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/pipeline.h"
-#include "src/compiler/simplified-lowering.h"
-#include "src/compiler/simplified-operator.h"
#include "src/compiler/source-position.h"
-#include "src/compiler/typer.h"
+#include "src/compiler/zone-pool.h"
#include "src/code-factory.h"
#include "src/code-stubs.h"
@@ -52,17 +49,11 @@
namespace {
const Operator* UnsupportedOpcode(wasm::WasmOpcode opcode) {
- if (wasm::WasmOpcodes::IsSupported(opcode)) {
- V8_Fatal(__FILE__, __LINE__,
- "Unsupported opcode #%d:%s reported as supported", opcode,
- wasm::WasmOpcodes::OpcodeName(opcode));
- }
V8_Fatal(__FILE__, __LINE__, "Unsupported opcode #%d:%s", opcode,
wasm::WasmOpcodes::OpcodeName(opcode));
return nullptr;
}
-
void MergeControlToEnd(JSGraph* jsgraph, Node* node) {
Graph* g = jsgraph->graph();
if (g->end()) {
@@ -83,62 +74,72 @@
explicit WasmTrapHelper(WasmGraphBuilder* builder)
: builder_(builder),
jsgraph_(builder->jsgraph()),
- graph_(builder->jsgraph() ? builder->jsgraph()->graph() : nullptr) {
- for (int i = 0; i < wasm::kTrapCount; i++) traps_[i] = nullptr;
- }
+ graph_(builder->jsgraph() ? builder->jsgraph()->graph() : nullptr) {}
// Make the current control path trap to unreachable.
- void Unreachable() { ConnectTrap(wasm::kTrapUnreachable); }
+ void Unreachable(wasm::WasmCodePosition position) {
+ ConnectTrap(wasm::kTrapUnreachable, position);
+ }
// Always trap with the given reason.
- void TrapAlways(wasm::TrapReason reason) { ConnectTrap(reason); }
+ void TrapAlways(wasm::TrapReason reason, wasm::WasmCodePosition position) {
+ ConnectTrap(reason, position);
+ }
// Add a check that traps if {node} is equal to {val}.
- Node* TrapIfEq32(wasm::TrapReason reason, Node* node, int32_t val) {
+ Node* TrapIfEq32(wasm::TrapReason reason, Node* node, int32_t val,
+ wasm::WasmCodePosition position) {
Int32Matcher m(node);
if (m.HasValue() && !m.Is(val)) return graph()->start();
if (val == 0) {
- AddTrapIfFalse(reason, node);
+ AddTrapIfFalse(reason, node, position);
} else {
AddTrapIfTrue(reason,
graph()->NewNode(jsgraph()->machine()->Word32Equal(), node,
- jsgraph()->Int32Constant(val)));
+ jsgraph()->Int32Constant(val)),
+ position);
}
return builder_->Control();
}
// Add a check that traps if {node} is zero.
- Node* ZeroCheck32(wasm::TrapReason reason, Node* node) {
- return TrapIfEq32(reason, node, 0);
+ Node* ZeroCheck32(wasm::TrapReason reason, Node* node,
+ wasm::WasmCodePosition position) {
+ return TrapIfEq32(reason, node, 0, position);
}
// Add a check that traps if {node} is equal to {val}.
- Node* TrapIfEq64(wasm::TrapReason reason, Node* node, int64_t val) {
+ Node* TrapIfEq64(wasm::TrapReason reason, Node* node, int64_t val,
+ wasm::WasmCodePosition position) {
Int64Matcher m(node);
if (m.HasValue() && !m.Is(val)) return graph()->start();
- AddTrapIfTrue(reason,
- graph()->NewNode(jsgraph()->machine()->Word64Equal(), node,
- jsgraph()->Int64Constant(val)));
+ AddTrapIfTrue(reason, graph()->NewNode(jsgraph()->machine()->Word64Equal(),
+ node, jsgraph()->Int64Constant(val)),
+ position);
return builder_->Control();
}
// Add a check that traps if {node} is zero.
- Node* ZeroCheck64(wasm::TrapReason reason, Node* node) {
- return TrapIfEq64(reason, node, 0);
+ Node* ZeroCheck64(wasm::TrapReason reason, Node* node,
+ wasm::WasmCodePosition position) {
+ return TrapIfEq64(reason, node, 0, position);
}
// Add a trap if {cond} is true.
- void AddTrapIfTrue(wasm::TrapReason reason, Node* cond) {
- AddTrapIf(reason, cond, true);
+ void AddTrapIfTrue(wasm::TrapReason reason, Node* cond,
+ wasm::WasmCodePosition position) {
+ AddTrapIf(reason, cond, true, position);
}
// Add a trap if {cond} is false.
- void AddTrapIfFalse(wasm::TrapReason reason, Node* cond) {
- AddTrapIf(reason, cond, false);
+ void AddTrapIfFalse(wasm::TrapReason reason, Node* cond,
+ wasm::WasmCodePosition position) {
+ AddTrapIf(reason, cond, false, position);
}
// Add a trap if {cond} is true or false according to {iftrue}.
- void AddTrapIf(wasm::TrapReason reason, Node* cond, bool iftrue) {
+ void AddTrapIf(wasm::TrapReason reason, Node* cond, bool iftrue,
+ wasm::WasmCodePosition position) {
Node** effect_ptr = builder_->effect_;
Node** control_ptr = builder_->control_;
Node* before = *effect_ptr;
@@ -148,7 +149,7 @@
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
*control_ptr = iftrue ? if_true : if_false;
- ConnectTrap(reason);
+ ConnectTrap(reason, position);
*control_ptr = iftrue ? if_false : if_true;
*effect_ptr = before;
}
@@ -179,49 +180,69 @@
WasmGraphBuilder* builder_;
JSGraph* jsgraph_;
Graph* graph_;
- Node* traps_[wasm::kTrapCount];
- Node* effects_[wasm::kTrapCount];
+ Node* trap_merge_ = nullptr;
+ Node* trap_effect_;
+ Node* trap_reason_;
+ Node* trap_position_;
JSGraph* jsgraph() { return jsgraph_; }
Graph* graph() { return jsgraph_->graph(); }
CommonOperatorBuilder* common() { return jsgraph()->common(); }
- void ConnectTrap(wasm::TrapReason reason) {
- if (traps_[reason] == nullptr) {
- // Create trap code for the first time this trap is used.
- return BuildTrapCode(reason);
+ void ConnectTrap(wasm::TrapReason reason, wasm::WasmCodePosition position) {
+ DCHECK(position != wasm::kNoCodePosition);
+ Node* reason_node = builder_->Int32Constant(
+ wasm::WasmOpcodes::TrapReasonToMessageId(reason));
+ Node* position_node = builder_->Int32Constant(position);
+ if (trap_merge_ == nullptr) {
+ // Create trap code for the first time.
+ return BuildTrapCode(reason_node, position_node);
}
// Connect the current control and effect to the existing trap code.
- builder_->AppendToMerge(traps_[reason], builder_->Control());
- builder_->AppendToPhi(traps_[reason], effects_[reason], builder_->Effect());
+ builder_->AppendToMerge(trap_merge_, builder_->Control());
+ builder_->AppendToPhi(trap_effect_, builder_->Effect());
+ builder_->AppendToPhi(trap_reason_, reason_node);
+ builder_->AppendToPhi(trap_position_, position_node);
}
- void BuildTrapCode(wasm::TrapReason reason) {
- Node* exception =
- builder_->String(wasm::WasmOpcodes::TrapReasonName(reason));
+ void BuildTrapCode(Node* reason_node, Node* position_node) {
Node* end;
Node** control_ptr = builder_->control_;
Node** effect_ptr = builder_->effect_;
wasm::ModuleEnv* module = builder_->module_;
- *control_ptr = traps_[reason] =
+ DCHECK(trap_merge_ == NULL);
+ *control_ptr = trap_merge_ =
graph()->NewNode(common()->Merge(1), *control_ptr);
- *effect_ptr = effects_[reason] =
+ *effect_ptr = trap_effect_ =
graph()->NewNode(common()->EffectPhi(1), *effect_ptr, *control_ptr);
+ trap_reason_ =
+ graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 1),
+ reason_node, *control_ptr);
+ trap_position_ =
+ graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 1),
+ position_node, *control_ptr);
+
+ Node* trap_reason_smi = builder_->BuildChangeInt32ToSmi(trap_reason_);
+ Node* trap_position_smi = builder_->BuildChangeInt32ToSmi(trap_position_);
if (module && !module->instance->context.is_null()) {
// Use the module context to call the runtime to throw an exception.
- Runtime::FunctionId f = Runtime::kThrow;
+ Runtime::FunctionId f = Runtime::kThrowWasmError;
const Runtime::Function* fun = Runtime::FunctionForId(f);
CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
jsgraph()->zone(), f, fun->nargs, Operator::kNoProperties,
CallDescriptor::kNoFlags);
+ // CEntryStubConstant nodes have to be created and cached in the main
+ // thread. At the moment this is only done for CEntryStubConstant(1).
+ DCHECK_EQ(1, fun->result_size);
Node* inputs[] = {
jsgraph()->CEntryStubConstant(fun->result_size), // C entry
- exception, // exception
+ trap_reason_smi, // message id
+ trap_position_smi, // byte position
jsgraph()->ExternalConstant(
- ExternalReference(f, jsgraph()->isolate())), // ref
- jsgraph()->Int32Constant(fun->nargs), // arity
- jsgraph()->Constant(module->instance->context), // context
+ ExternalReference(f, jsgraph()->isolate())), // ref
+ jsgraph()->Int32Constant(fun->nargs), // arity
+ builder_->HeapConstant(module->instance->context), // context
*effect_ptr,
*control_ptr};
@@ -247,8 +268,9 @@
}
};
-WasmGraphBuilder::WasmGraphBuilder(Zone* zone, JSGraph* jsgraph,
- wasm::FunctionSig* function_signature)
+WasmGraphBuilder::WasmGraphBuilder(
+ Zone* zone, JSGraph* jsgraph, wasm::FunctionSig* function_signature,
+ compiler::SourcePositionTable* source_position_table)
: zone_(zone),
jsgraph_(jsgraph),
module_(nullptr),
@@ -260,32 +282,28 @@
cur_buffer_(def_buffer_),
cur_bufsize_(kDefaultBufferSize),
trap_(new (zone) WasmTrapHelper(this)),
- function_signature_(function_signature) {
+ function_signature_(function_signature),
+ source_position_table_(source_position_table) {
DCHECK_NOT_NULL(jsgraph_);
}
-
Node* WasmGraphBuilder::Error() { return jsgraph()->Dead(); }
-
Node* WasmGraphBuilder::Start(unsigned params) {
Node* start = graph()->NewNode(jsgraph()->common()->Start(params));
graph()->SetStart(start);
return start;
}
-
Node* WasmGraphBuilder::Param(unsigned index, wasm::LocalType type) {
return graph()->NewNode(jsgraph()->common()->Parameter(index),
graph()->start());
}
-
Node* WasmGraphBuilder::Loop(Node* entry) {
return graph()->NewNode(jsgraph()->common()->Loop(1), entry);
}
-
Node* WasmGraphBuilder::Terminate(Node* effect, Node* control) {
Node* terminate =
graph()->NewNode(jsgraph()->common()->Terminate(), effect, control);
@@ -293,18 +311,15 @@
return terminate;
}
-
unsigned WasmGraphBuilder::InputCount(Node* node) {
return static_cast<unsigned>(node->InputCount());
}
-
bool WasmGraphBuilder::IsPhiWithMerge(Node* phi, Node* merge) {
return phi && IrOpcode::IsPhiOpcode(phi->opcode()) &&
NodeProperties::GetControlInput(phi) == merge;
}
-
void WasmGraphBuilder::AppendToMerge(Node* merge, Node* from) {
DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
merge->AppendInput(jsgraph()->zone(), from);
@@ -313,22 +328,18 @@
merge, jsgraph()->common()->ResizeMergeOrPhi(merge->op(), new_size));
}
-
-void WasmGraphBuilder::AppendToPhi(Node* merge, Node* phi, Node* from) {
+void WasmGraphBuilder::AppendToPhi(Node* phi, Node* from) {
DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
- DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
int new_size = phi->InputCount();
phi->InsertInput(jsgraph()->zone(), phi->InputCount() - 1, from);
NodeProperties::ChangeOp(
phi, jsgraph()->common()->ResizeMergeOrPhi(phi->op(), new_size));
}
-
Node* WasmGraphBuilder::Merge(unsigned count, Node** controls) {
return graph()->NewNode(jsgraph()->common()->Merge(count), count, controls);
}
-
Node* WasmGraphBuilder::Phi(wasm::LocalType type, unsigned count, Node** vals,
Node* control) {
DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
@@ -338,7 +349,6 @@
buf);
}
-
Node* WasmGraphBuilder::EffectPhi(unsigned count, Node** effects,
Node* control) {
DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
@@ -348,19 +358,20 @@
buf);
}
+Node* WasmGraphBuilder::NumberConstant(int32_t value) {
+ return jsgraph()->Constant(value);
+}
Node* WasmGraphBuilder::Int32Constant(int32_t value) {
return jsgraph()->Int32Constant(value);
}
-
Node* WasmGraphBuilder::Int64Constant(int64_t value) {
return jsgraph()->Int64Constant(value);
}
-
-Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left,
- Node* right) {
+Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, Node* right,
+ wasm::WasmCodePosition position) {
const Operator* op;
MachineOperatorBuilder* m = jsgraph()->machine();
switch (opcode) {
@@ -374,13 +385,13 @@
op = m->Int32Mul();
break;
case wasm::kExprI32DivS:
- return BuildI32DivS(left, right);
+ return BuildI32DivS(left, right, position);
case wasm::kExprI32DivU:
- return BuildI32DivU(left, right);
+ return BuildI32DivU(left, right, position);
case wasm::kExprI32RemS:
- return BuildI32RemS(left, right);
+ return BuildI32RemS(left, right, position);
case wasm::kExprI32RemU:
- return BuildI32RemU(left, right);
+ return BuildI32RemU(left, right, position);
case wasm::kExprI32And:
op = m->Word32And();
break;
@@ -445,62 +456,46 @@
case wasm::kExprI64And:
op = m->Word64And();
break;
- // 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;
- // kExprI64DivS:
case wasm::kExprI64DivS:
- return BuildI64DivS(left, right);
- // kExprI64DivU:
+ return BuildI64DivS(left, right, position);
case wasm::kExprI64DivU:
- return BuildI64DivU(left, right);
- // kExprI64RemS:
+ return BuildI64DivU(left, right, position);
case wasm::kExprI64RemS:
- return BuildI64RemS(left, right);
- // kExprI64RemU:
+ return BuildI64RemS(left, right, position);
case wasm::kExprI64RemU:
- return BuildI64RemU(left, right);
+ return BuildI64RemU(left, right, position);
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;
@@ -543,7 +538,7 @@
op = m->Float32Add();
break;
case wasm::kExprF32Sub:
- op = m->Float32Sub();
+ op = m->Float32SubPreserveNan();
break;
case wasm::kExprF32Mul:
op = m->Float32Mul();
@@ -574,7 +569,7 @@
op = m->Float64Add();
break;
case wasm::kExprF64Sub:
- op = m->Float64Sub();
+ op = m->Float64SubPreserveNan();
break;
case wasm::kExprF64Mul:
op = m->Float64Mul();
@@ -609,23 +604,38 @@
return BuildF32Max(left, right);
case wasm::kExprF64Max:
return BuildF64Max(left, right);
- case wasm::kExprF64Pow: {
+ case wasm::kExprF64Pow:
return BuildF64Pow(left, right);
- }
- case wasm::kExprF64Atan2: {
+ case wasm::kExprF64Atan2:
return BuildF64Atan2(left, right);
- }
- case wasm::kExprF64Mod: {
+ case wasm::kExprF64Mod:
return BuildF64Mod(left, right);
- }
+ case wasm::kExprI32AsmjsDivS:
+ return BuildI32AsmjsDivS(left, right);
+ case wasm::kExprI32AsmjsDivU:
+ return BuildI32AsmjsDivU(left, right);
+ case wasm::kExprI32AsmjsRemS:
+ return BuildI32AsmjsRemS(left, right);
+ case wasm::kExprI32AsmjsRemU:
+ return BuildI32AsmjsRemU(left, right);
+ case wasm::kExprI32AsmjsStoreMem8:
+ return BuildAsmjsStoreMem(MachineType::Int8(), left, right);
+ case wasm::kExprI32AsmjsStoreMem16:
+ return BuildAsmjsStoreMem(MachineType::Int16(), left, right);
+ case wasm::kExprI32AsmjsStoreMem:
+ return BuildAsmjsStoreMem(MachineType::Int32(), left, right);
+ case wasm::kExprF32AsmjsStoreMem:
+ return BuildAsmjsStoreMem(MachineType::Float32(), left, right);
+ case wasm::kExprF64AsmjsStoreMem:
+ return BuildAsmjsStoreMem(MachineType::Float64(), left, right);
default:
op = UnsupportedOpcode(opcode);
}
return graph()->NewNode(op, left, right);
}
-
-Node* WasmGraphBuilder::Unop(wasm::WasmOpcode opcode, Node* input) {
+Node* WasmGraphBuilder::Unop(wasm::WasmOpcode opcode, Node* input,
+ wasm::WasmCodePosition position) {
const Operator* op;
MachineOperatorBuilder* m = jsgraph()->machine();
switch (opcode) {
@@ -649,9 +659,13 @@
op = m->Float64Sqrt();
break;
case wasm::kExprI32SConvertF64:
- return BuildI32SConvertF64(input);
+ return BuildI32SConvertF64(input, position);
case wasm::kExprI32UConvertF64:
- return BuildI32UConvertF64(input);
+ return BuildI32UConvertF64(input, position);
+ case wasm::kExprI32AsmjsSConvertF64:
+ return BuildI32AsmjsSConvertF64(input);
+ case wasm::kExprI32AsmjsUConvertF64:
+ return BuildI32AsmjsUConvertF64(input);
case wasm::kExprF32ConvertF64:
op = m->TruncateFloat64ToFloat32();
break;
@@ -668,9 +682,13 @@
op = m->RoundUint32ToFloat32();
break;
case wasm::kExprI32SConvertF32:
- return BuildI32SConvertF32(input);
+ return BuildI32SConvertF32(input, position);
case wasm::kExprI32UConvertF32:
- return BuildI32UConvertF32(input);
+ return BuildI32UConvertF32(input, position);
+ case wasm::kExprI32AsmjsSConvertF32:
+ return BuildI32AsmjsSConvertF32(input);
+ case wasm::kExprI32AsmjsUConvertF32:
+ return BuildI32AsmjsUConvertF32(input);
case wasm::kExprF64ConvertF32:
op = m->ChangeFloat32ToFloat64();
break;
@@ -769,31 +787,24 @@
case wasm::kExprF64Log: {
return BuildF64Log(input);
}
- // kExprI32ConvertI64:
case wasm::kExprI32ConvertI64:
op = m->TruncateInt64ToInt32();
break;
- // kExprI64SConvertI32:
case wasm::kExprI64SConvertI32:
op = m->ChangeInt32ToInt64();
break;
- // kExprI64UConvertI32:
case wasm::kExprI64UConvertI32:
op = m->ChangeUint32ToUint64();
break;
- // 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();
@@ -809,7 +820,6 @@
return BuildI64Ctz(input);
}
}
- // kExprI64Popcnt:
case wasm::kExprI64Popcnt: {
if (m->Word64Popcnt().IsSupported()) {
op = m->Word64Popcnt().op();
@@ -820,7 +830,6 @@
}
break;
}
- // kExprF32SConvertI64:
case wasm::kExprI64Eqz:
op = m->Word64Equal();
return graph()->NewNode(op, input, jsgraph()->Int64Constant(0));
@@ -830,65 +839,64 @@
}
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);
- }
+ case wasm::kExprI64SConvertF32:
+ return BuildI64SConvertF32(input, position);
+ case wasm::kExprI64SConvertF64:
+ return BuildI64SConvertF64(input, position);
+ case wasm::kExprI64UConvertF32:
+ return BuildI64UConvertF32(input, position);
+ case wasm::kExprI64UConvertF64:
+ return BuildI64UConvertF64(input, position);
+ case wasm::kExprI32AsmjsLoadMem8S:
+ return BuildAsmjsLoadMem(MachineType::Int8(), input);
+ case wasm::kExprI32AsmjsLoadMem8U:
+ return BuildAsmjsLoadMem(MachineType::Uint8(), input);
+ case wasm::kExprI32AsmjsLoadMem16S:
+ return BuildAsmjsLoadMem(MachineType::Int16(), input);
+ case wasm::kExprI32AsmjsLoadMem16U:
+ return BuildAsmjsLoadMem(MachineType::Uint16(), input);
+ case wasm::kExprI32AsmjsLoadMem:
+ return BuildAsmjsLoadMem(MachineType::Int32(), input);
+ case wasm::kExprF32AsmjsLoadMem:
+ return BuildAsmjsLoadMem(MachineType::Float32(), input);
+ case wasm::kExprF64AsmjsLoadMem:
+ return BuildAsmjsLoadMem(MachineType::Float64(), input);
default:
op = UnsupportedOpcode(opcode);
}
return graph()->NewNode(op, input);
}
-
Node* WasmGraphBuilder::Float32Constant(float value) {
return jsgraph()->Float32Constant(value);
}
-
Node* WasmGraphBuilder::Float64Constant(double value) {
return jsgraph()->Float64Constant(value);
}
-
-Node* WasmGraphBuilder::Constant(Handle<Object> value) {
- return jsgraph()->Constant(value);
+Node* WasmGraphBuilder::HeapConstant(Handle<HeapObject> value) {
+ return jsgraph()->HeapConstant(value);
}
-
Node* WasmGraphBuilder::Branch(Node* cond, Node** true_node,
Node** false_node) {
DCHECK_NOT_NULL(cond);
@@ -900,24 +908,20 @@
return branch;
}
-
Node* WasmGraphBuilder::Switch(unsigned count, Node* key) {
return graph()->NewNode(jsgraph()->common()->Switch(count), key, *control_);
}
-
Node* WasmGraphBuilder::IfValue(int32_t value, Node* sw) {
DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
return graph()->NewNode(jsgraph()->common()->IfValue(value), sw);
}
-
Node* WasmGraphBuilder::IfDefault(Node* sw) {
DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
return graph()->NewNode(jsgraph()->common()->IfDefault(), sw);
}
-
Node* WasmGraphBuilder::Return(unsigned count, Node** vals) {
DCHECK_NOT_NULL(*control_);
DCHECK_NOT_NULL(*effect_);
@@ -937,12 +941,10 @@
return ret;
}
-
Node* WasmGraphBuilder::ReturnVoid() { return Return(0, Buffer(0)); }
-
-Node* WasmGraphBuilder::Unreachable() {
- trap_->Unreachable();
+Node* WasmGraphBuilder::Unreachable(wasm::WasmCodePosition position) {
+ trap_->Unreachable(position);
return nullptr;
}
@@ -987,7 +989,6 @@
return result;
}
-
Node* WasmGraphBuilder::BuildF64Neg(Node* input) {
#if WASM_64
Node* result =
@@ -1007,7 +1008,6 @@
#endif
}
-
Node* WasmGraphBuilder::BuildF32CopySign(Node* left, Node* right) {
Node* result = Unop(
wasm::kExprF32ReinterpretI32,
@@ -1020,7 +1020,6 @@
return result;
}
-
Node* WasmGraphBuilder::BuildF64CopySign(Node* left, Node* right) {
#if WASM_64
Node* result = Unop(
@@ -1049,7 +1048,6 @@
#endif
}
-
Node* WasmGraphBuilder::BuildF32Min(Node* left, Node* right) {
Diamond left_le_right(graph(), jsgraph()->common(),
Binop(wasm::kExprF32Le, left, right));
@@ -1070,7 +1068,6 @@
Binop(wasm::kExprF32Mul, left, Float32Constant(1.0)))));
}
-
Node* WasmGraphBuilder::BuildF32Max(Node* left, Node* right) {
Diamond left_ge_right(graph(), jsgraph()->common(),
Binop(wasm::kExprF32Ge, left, right));
@@ -1091,7 +1088,6 @@
Binop(wasm::kExprF32Mul, left, Float32Constant(1.0)))));
}
-
Node* WasmGraphBuilder::BuildF64Min(Node* left, Node* right) {
Diamond left_le_right(graph(), jsgraph()->common(),
Binop(wasm::kExprF64Le, left, right));
@@ -1112,7 +1108,6 @@
Binop(wasm::kExprF64Mul, left, Float64Constant(1.0)))));
}
-
Node* WasmGraphBuilder::BuildF64Max(Node* left, Node* right) {
Diamond left_ge_right(graph(), jsgraph()->common(),
Binop(wasm::kExprF64Ge, left, right));
@@ -1133,16 +1128,9 @@
Binop(wasm::kExprF64Mul, left, Float64Constant(1.0)))));
}
-
-Node* WasmGraphBuilder::BuildI32SConvertF32(Node* input) {
+Node* WasmGraphBuilder::BuildI32SConvertF32(Node* input,
+ wasm::WasmCodePosition position) {
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);
@@ -1151,19 +1139,14 @@
// 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(wasm::kTrapFloatUnrepresentable, overflow);
+ trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
return result;
}
-
-Node* WasmGraphBuilder::BuildI32SConvertF64(Node* input) {
+Node* WasmGraphBuilder::BuildI32SConvertF64(Node* input,
+ wasm::WasmCodePosition position) {
MachineOperatorBuilder* m = jsgraph()->machine();
- 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->ChangeFloat64ToInt32(), trunc);
@@ -1172,21 +1155,14 @@
// 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(wasm::kTrapFloatUnrepresentable, overflow);
+ trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
return result;
}
-
-Node* WasmGraphBuilder::BuildI32UConvertF32(Node* input) {
+Node* WasmGraphBuilder::BuildI32UConvertF32(Node* input,
+ wasm::WasmCodePosition position) {
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);
@@ -1195,19 +1171,14 @@
// 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(wasm::kTrapFloatUnrepresentable, overflow);
+ trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
return result;
}
-
-Node* WasmGraphBuilder::BuildI32UConvertF64(Node* input) {
+Node* WasmGraphBuilder::BuildI32UConvertF64(Node* input,
+ wasm::WasmCodePosition position) {
MachineOperatorBuilder* m = jsgraph()->machine();
- 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->TruncateFloat64ToUint32(), trunc);
@@ -1216,185 +1187,82 @@
// 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(wasm::kTrapFloatUnrepresentable, overflow);
+ trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
return result;
}
+Node* WasmGraphBuilder::BuildI32AsmjsSConvertF32(Node* input) {
+ MachineOperatorBuilder* m = jsgraph()->machine();
+ // asm.js must use the wacky JS semantics.
+ input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input);
+ return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
+}
+
+Node* WasmGraphBuilder::BuildI32AsmjsSConvertF64(Node* input) {
+ MachineOperatorBuilder* m = jsgraph()->machine();
+ // asm.js must use the wacky JS semantics.
+ return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
+}
+
+Node* WasmGraphBuilder::BuildI32AsmjsUConvertF32(Node* input) {
+ MachineOperatorBuilder* m = jsgraph()->machine();
+ // asm.js must use the wacky JS semantics.
+ input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input);
+ return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
+}
+
+Node* WasmGraphBuilder::BuildI32AsmjsUConvertF64(Node* input) {
+ MachineOperatorBuilder* m = jsgraph()->machine();
+ // asm.js must use the wacky JS semantics.
+ return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
+}
+
+Node* WasmGraphBuilder::BuildBitCountingCall(Node* input, ExternalReference ref,
+ MachineRepresentation input_type) {
+ Node* stack_slot_param =
+ graph()->NewNode(jsgraph()->machine()->StackSlot(input_type));
+
+ const Operator* store_op = jsgraph()->machine()->Store(
+ StoreRepresentation(input_type, kNoWriteBarrier));
+ *effect_ =
+ graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
+ input, *effect_, *control_);
+
+ MachineSignature::Builder sig_builder(jsgraph()->zone(), 1, 1);
+ sig_builder.AddReturn(MachineType::Int32());
+ sig_builder.AddParam(MachineType::Pointer());
+
+ Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
+ Node* args[] = {function, stack_slot_param};
+
+ return BuildCCall(sig_builder.Build(), args);
+}
Node* WasmGraphBuilder::BuildI32Ctz(Node* input) {
- //// Implement the following code as TF graph.
- // value = value | (value << 1);
- // value = value | (value << 2);
- // value = value | (value << 4);
- // value = value | (value << 8);
- // value = value | (value << 16);
- // return CountPopulation32(0xffffffff XOR value);
-
- Node* result =
- Binop(wasm::kExprI32Ior, input,
- Binop(wasm::kExprI32Shl, input, jsgraph()->Int32Constant(1)));
-
- result = Binop(wasm::kExprI32Ior, result,
- Binop(wasm::kExprI32Shl, result, jsgraph()->Int32Constant(2)));
-
- result = Binop(wasm::kExprI32Ior, result,
- Binop(wasm::kExprI32Shl, result, jsgraph()->Int32Constant(4)));
-
- result = Binop(wasm::kExprI32Ior, result,
- Binop(wasm::kExprI32Shl, result, jsgraph()->Int32Constant(8)));
-
- result =
- Binop(wasm::kExprI32Ior, result,
- Binop(wasm::kExprI32Shl, result, jsgraph()->Int32Constant(16)));
-
- result = BuildI32Popcnt(
- Binop(wasm::kExprI32Xor, jsgraph()->Int32Constant(0xffffffff), result));
-
- return result;
+ return BuildBitCountingCall(
+ input, ExternalReference::wasm_word32_ctz(jsgraph()->isolate()),
+ MachineRepresentation::kWord32);
}
-
Node* WasmGraphBuilder::BuildI64Ctz(Node* input) {
- //// Implement the following code as TF graph.
- // value = value | (value << 1);
- // value = value | (value << 2);
- // value = value | (value << 4);
- // value = value | (value << 8);
- // value = value | (value << 16);
- // value = value | (value << 32);
- // return CountPopulation64(0xffffffffffffffff XOR value);
-
- Node* result =
- Binop(wasm::kExprI64Ior, input,
- Binop(wasm::kExprI64Shl, input, jsgraph()->Int64Constant(1)));
-
- result = Binop(wasm::kExprI64Ior, result,
- Binop(wasm::kExprI64Shl, result, jsgraph()->Int64Constant(2)));
-
- result = Binop(wasm::kExprI64Ior, result,
- Binop(wasm::kExprI64Shl, result, jsgraph()->Int64Constant(4)));
-
- result = Binop(wasm::kExprI64Ior, result,
- Binop(wasm::kExprI64Shl, result, jsgraph()->Int64Constant(8)));
-
- result =
- Binop(wasm::kExprI64Ior, result,
- Binop(wasm::kExprI64Shl, result, jsgraph()->Int64Constant(16)));
-
- result =
- Binop(wasm::kExprI64Ior, result,
- Binop(wasm::kExprI64Shl, result, jsgraph()->Int64Constant(32)));
-
- result = BuildI64Popcnt(Binop(
- wasm::kExprI64Xor, jsgraph()->Int64Constant(0xffffffffffffffff), result));
-
- return result;
+ return Unop(wasm::kExprI64UConvertI32,
+ BuildBitCountingCall(input, ExternalReference::wasm_word64_ctz(
+ jsgraph()->isolate()),
+ MachineRepresentation::kWord64));
}
-
Node* WasmGraphBuilder::BuildI32Popcnt(Node* input) {
- //// Implement the following code as a TF graph.
- // value = ((value >> 1) & 0x55555555) + (value & 0x55555555);
- // value = ((value >> 2) & 0x33333333) + (value & 0x33333333);
- // value = ((value >> 4) & 0x0f0f0f0f) + (value & 0x0f0f0f0f);
- // value = ((value >> 8) & 0x00ff00ff) + (value & 0x00ff00ff);
- // value = ((value >> 16) & 0x0000ffff) + (value & 0x0000ffff);
-
- Node* result = Binop(
- wasm::kExprI32Add,
- Binop(wasm::kExprI32And,
- Binop(wasm::kExprI32ShrU, input, jsgraph()->Int32Constant(1)),
- jsgraph()->Int32Constant(0x55555555)),
- Binop(wasm::kExprI32And, input, jsgraph()->Int32Constant(0x55555555)));
-
- result = Binop(
- wasm::kExprI32Add,
- Binop(wasm::kExprI32And,
- Binop(wasm::kExprI32ShrU, result, jsgraph()->Int32Constant(2)),
- jsgraph()->Int32Constant(0x33333333)),
- Binop(wasm::kExprI32And, result, jsgraph()->Int32Constant(0x33333333)));
-
- result = Binop(
- wasm::kExprI32Add,
- Binop(wasm::kExprI32And,
- Binop(wasm::kExprI32ShrU, result, jsgraph()->Int32Constant(4)),
- jsgraph()->Int32Constant(0x0f0f0f0f)),
- Binop(wasm::kExprI32And, result, jsgraph()->Int32Constant(0x0f0f0f0f)));
-
- result = Binop(
- wasm::kExprI32Add,
- Binop(wasm::kExprI32And,
- Binop(wasm::kExprI32ShrU, result, jsgraph()->Int32Constant(8)),
- jsgraph()->Int32Constant(0x00ff00ff)),
- Binop(wasm::kExprI32And, result, jsgraph()->Int32Constant(0x00ff00ff)));
-
- result = Binop(
- wasm::kExprI32Add,
- Binop(wasm::kExprI32And,
- Binop(wasm::kExprI32ShrU, result, jsgraph()->Int32Constant(16)),
- jsgraph()->Int32Constant(0x0000ffff)),
- Binop(wasm::kExprI32And, result, jsgraph()->Int32Constant(0x0000ffff)));
-
- return result;
+ return BuildBitCountingCall(
+ input, ExternalReference::wasm_word32_popcnt(jsgraph()->isolate()),
+ MachineRepresentation::kWord32);
}
-
Node* WasmGraphBuilder::BuildI64Popcnt(Node* input) {
- //// Implement the following code as a TF graph.
- // value = ((value >> 1) & 0x5555555555555555) + (value & 0x5555555555555555);
- // value = ((value >> 2) & 0x3333333333333333) + (value & 0x3333333333333333);
- // value = ((value >> 4) & 0x0f0f0f0f0f0f0f0f) + (value & 0x0f0f0f0f0f0f0f0f);
- // value = ((value >> 8) & 0x00ff00ff00ff00ff) + (value & 0x00ff00ff00ff00ff);
- // value = ((value >> 16) & 0x0000ffff0000ffff) + (value &
- // 0x0000ffff0000ffff);
- // value = ((value >> 32) & 0x00000000ffffffff) + (value &
- // 0x00000000ffffffff);
-
- Node* result =
- Binop(wasm::kExprI64Add,
- Binop(wasm::kExprI64And,
- Binop(wasm::kExprI64ShrU, input, jsgraph()->Int64Constant(1)),
- jsgraph()->Int64Constant(0x5555555555555555)),
- Binop(wasm::kExprI64And, input,
- jsgraph()->Int64Constant(0x5555555555555555)));
-
- result = Binop(wasm::kExprI64Add,
- Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
- jsgraph()->Int64Constant(2)),
- jsgraph()->Int64Constant(0x3333333333333333)),
- Binop(wasm::kExprI64And, result,
- jsgraph()->Int64Constant(0x3333333333333333)));
-
- result = Binop(wasm::kExprI64Add,
- Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
- jsgraph()->Int64Constant(4)),
- jsgraph()->Int64Constant(0x0f0f0f0f0f0f0f0f)),
- Binop(wasm::kExprI64And, result,
- jsgraph()->Int64Constant(0x0f0f0f0f0f0f0f0f)));
-
- result = Binop(wasm::kExprI64Add,
- Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
- jsgraph()->Int64Constant(8)),
- jsgraph()->Int64Constant(0x00ff00ff00ff00ff)),
- Binop(wasm::kExprI64And, result,
- jsgraph()->Int64Constant(0x00ff00ff00ff00ff)));
-
- result = Binop(wasm::kExprI64Add,
- Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
- jsgraph()->Int64Constant(16)),
- jsgraph()->Int64Constant(0x0000ffff0000ffff)),
- Binop(wasm::kExprI64And, result,
- jsgraph()->Int64Constant(0x0000ffff0000ffff)));
-
- result = Binop(wasm::kExprI64Add,
- Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
- jsgraph()->Int64Constant(32)),
- jsgraph()->Int64Constant(0x00000000ffffffff)),
- Binop(wasm::kExprI64And, result,
- jsgraph()->Int64Constant(0x00000000ffffffff)));
-
- return result;
+ return Unop(wasm::kExprI64UConvertI32,
+ BuildBitCountingCall(input, ExternalReference::wasm_word64_popcnt(
+ jsgraph()->isolate()),
+ MachineRepresentation::kWord64));
}
Node* WasmGraphBuilder::BuildF32Trunc(Node* input) {
@@ -1635,66 +1503,70 @@
return load;
}
-Node* WasmGraphBuilder::BuildI64SConvertF32(Node* input) {
+Node* WasmGraphBuilder::BuildI64SConvertF32(Node* input,
+ wasm::WasmCodePosition position) {
if (jsgraph()->machine()->Is32()) {
return BuildFloatToIntConversionInstruction(
input, ExternalReference::wasm_float32_to_int64(jsgraph()->isolate()),
- MachineRepresentation::kFloat32, MachineType::Int64());
+ MachineRepresentation::kFloat32, MachineType::Int64(), position);
} 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);
+ trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
return result;
}
}
-Node* WasmGraphBuilder::BuildI64UConvertF32(Node* input) {
+Node* WasmGraphBuilder::BuildI64UConvertF32(Node* input,
+ wasm::WasmCodePosition position) {
if (jsgraph()->machine()->Is32()) {
return BuildFloatToIntConversionInstruction(
input, ExternalReference::wasm_float32_to_uint64(jsgraph()->isolate()),
- MachineRepresentation::kFloat32, MachineType::Int64());
+ MachineRepresentation::kFloat32, MachineType::Int64(), position);
} 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);
+ trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
return result;
}
}
-Node* WasmGraphBuilder::BuildI64SConvertF64(Node* input) {
+Node* WasmGraphBuilder::BuildI64SConvertF64(Node* input,
+ wasm::WasmCodePosition position) {
if (jsgraph()->machine()->Is32()) {
return BuildFloatToIntConversionInstruction(
input, ExternalReference::wasm_float64_to_int64(jsgraph()->isolate()),
- MachineRepresentation::kFloat64, MachineType::Int64());
+ MachineRepresentation::kFloat64, MachineType::Int64(), position);
} 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);
+ trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
return result;
}
}
-Node* WasmGraphBuilder::BuildI64UConvertF64(Node* input) {
+Node* WasmGraphBuilder::BuildI64UConvertF64(Node* input,
+ wasm::WasmCodePosition position) {
if (jsgraph()->machine()->Is32()) {
return BuildFloatToIntConversionInstruction(
input, ExternalReference::wasm_float64_to_uint64(jsgraph()->isolate()),
- MachineRepresentation::kFloat64, MachineType::Int64());
+ MachineRepresentation::kFloat64, MachineType::Int64(), position);
} 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);
+ trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
return result;
}
}
@@ -1702,7 +1574,7 @@
Node* WasmGraphBuilder::BuildFloatToIntConversionInstruction(
Node* input, ExternalReference ref,
MachineRepresentation parameter_representation,
- const MachineType result_type) {
+ const MachineType result_type, wasm::WasmCodePosition position) {
Node* stack_slot_param = graph()->NewNode(
jsgraph()->machine()->StackSlot(parameter_representation));
Node* stack_slot_result = graph()->NewNode(
@@ -1719,7 +1591,7 @@
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));
+ BuildCCall(sig_builder.Build(), args), position);
const Operator* load_op = jsgraph()->machine()->Load(result_type);
Node* load =
graph()->NewNode(load_op, stack_slot_result, jsgraph()->Int32Constant(0),
@@ -1728,37 +1600,10 @@
return load;
}
-Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right) {
+Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right,
+ wasm::WasmCodePosition position) {
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);
+ trap_->ZeroCheck32(wasm::kTrapDivByZero, right, position);
Node* before = *control_;
Node* denom_is_m1;
Node* denom_is_not_m1;
@@ -1766,7 +1611,7 @@
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);
+ trap_->TrapIfEq32(wasm::kTrapDivUnrepresentable, left, kMinInt, position);
if (*control_ != denom_is_m1) {
*control_ = graph()->NewNode(jsgraph()->common()->Merge(2), denom_is_not_m1,
*control_);
@@ -1776,30 +1621,11 @@
return graph()->NewNode(m->Int32Div(), left, right, *control_);
}
-Node* WasmGraphBuilder::BuildI32RemS(Node* left, Node* right) {
+Node* WasmGraphBuilder::BuildI32RemS(Node* left, Node* right,
+ wasm::WasmCodePosition position) {
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);
+ trap_->ZeroCheck32(wasm::kTrapRemByZero, right, position);
Diamond d(
graph(), jsgraph()->common(),
@@ -1811,56 +1637,115 @@
graph()->NewNode(m->Int32Mod(), left, right, d.if_false));
}
-Node* WasmGraphBuilder::BuildI32DivU(Node* left, Node* right) {
+Node* WasmGraphBuilder::BuildI32DivU(Node* left, Node* right,
+ wasm::WasmCodePosition position) {
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));
+ return graph()->NewNode(
+ m->Uint32Div(), left, right,
+ trap_->ZeroCheck32(wasm::kTrapDivByZero, right, position));
}
-Node* WasmGraphBuilder::BuildI32RemU(Node* left, Node* right) {
+Node* WasmGraphBuilder::BuildI32RemU(Node* left, Node* right,
+ wasm::WasmCodePosition position) {
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));
+ return graph()->NewNode(
+ m->Uint32Mod(), left, right,
+ trap_->ZeroCheck32(wasm::kTrapRemByZero, right, position));
}
-Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right) {
+Node* WasmGraphBuilder::BuildI32AsmjsDivS(Node* left, Node* right) {
+ MachineOperatorBuilder* m = jsgraph()->machine();
+ // 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));
+}
+
+Node* WasmGraphBuilder::BuildI32AsmjsRemS(Node* left, Node* right) {
+ MachineOperatorBuilder* m = jsgraph()->machine();
+ // 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)));
+}
+
+Node* WasmGraphBuilder::BuildI32AsmjsDivU(Node* left, Node* right) {
+ MachineOperatorBuilder* m = jsgraph()->machine();
+ // 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));
+}
+
+Node* WasmGraphBuilder::BuildI32AsmjsRemU(Node* left, Node* right) {
+ MachineOperatorBuilder* m = jsgraph()->machine();
+ // 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);
+}
+
+Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right,
+ wasm::WasmCodePosition position) {
if (jsgraph()->machine()->Is32()) {
return BuildDiv64Call(
left, right, ExternalReference::wasm_int64_div(jsgraph()->isolate()),
- MachineType::Int64(), wasm::kTrapDivByZero);
+ MachineType::Int64(), wasm::kTrapDivByZero, position);
}
- trap_->ZeroCheck64(wasm::kTrapDivByZero, right);
+ trap_->ZeroCheck64(wasm::kTrapDivByZero, right, position);
Node* before = *control_;
Node* denom_is_m1;
Node* denom_is_not_m1;
@@ -1869,7 +1754,7 @@
&denom_is_m1, &denom_is_not_m1);
*control_ = denom_is_m1;
trap_->TrapIfEq64(wasm::kTrapDivUnrepresentable, left,
- std::numeric_limits<int64_t>::min());
+ std::numeric_limits<int64_t>::min(), position);
if (*control_ != denom_is_m1) {
*control_ = graph()->NewNode(jsgraph()->common()->Merge(2), denom_is_not_m1,
*control_);
@@ -1880,13 +1765,14 @@
*control_);
}
-Node* WasmGraphBuilder::BuildI64RemS(Node* left, Node* right) {
+Node* WasmGraphBuilder::BuildI64RemS(Node* left, Node* right,
+ wasm::WasmCodePosition position) {
if (jsgraph()->machine()->Is32()) {
return BuildDiv64Call(
left, right, ExternalReference::wasm_int64_mod(jsgraph()->isolate()),
- MachineType::Int64(), wasm::kTrapRemByZero);
+ MachineType::Int64(), wasm::kTrapRemByZero, position);
}
- trap_->ZeroCheck64(wasm::kTrapRemByZero, right);
+ trap_->ZeroCheck64(wasm::kTrapRemByZero, right, position);
Diamond d(jsgraph()->graph(), jsgraph()->common(),
graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
jsgraph()->Int64Constant(-1)));
@@ -1898,28 +1784,33 @@
rem);
}
-Node* WasmGraphBuilder::BuildI64DivU(Node* left, Node* right) {
+Node* WasmGraphBuilder::BuildI64DivU(Node* left, Node* right,
+ wasm::WasmCodePosition position) {
if (jsgraph()->machine()->Is32()) {
return BuildDiv64Call(
left, right, ExternalReference::wasm_uint64_div(jsgraph()->isolate()),
- MachineType::Int64(), wasm::kTrapDivByZero);
+ MachineType::Int64(), wasm::kTrapDivByZero, position);
}
- return graph()->NewNode(jsgraph()->machine()->Uint64Div(), left, right,
- trap_->ZeroCheck64(wasm::kTrapDivByZero, right));
+ return graph()->NewNode(
+ jsgraph()->machine()->Uint64Div(), left, right,
+ trap_->ZeroCheck64(wasm::kTrapDivByZero, right, position));
}
-Node* WasmGraphBuilder::BuildI64RemU(Node* left, Node* right) {
+Node* WasmGraphBuilder::BuildI64RemU(Node* left, Node* right,
+ wasm::WasmCodePosition position) {
if (jsgraph()->machine()->Is32()) {
return BuildDiv64Call(
left, right, ExternalReference::wasm_uint64_mod(jsgraph()->isolate()),
- MachineType::Int64(), wasm::kTrapRemByZero);
+ MachineType::Int64(), wasm::kTrapRemByZero, position);
}
- return graph()->NewNode(jsgraph()->machine()->Uint64Mod(), left, right,
- trap_->ZeroCheck64(wasm::kTrapRemByZero, right));
+ return graph()->NewNode(
+ jsgraph()->machine()->Uint64Mod(), left, right,
+ trap_->ZeroCheck64(wasm::kTrapRemByZero, right, position));
}
Node* WasmGraphBuilder::BuildDiv64Call(Node* left, Node* right,
ExternalReference ref,
- MachineType result_type, int trap_zero) {
+ MachineType result_type, int trap_zero,
+ wasm::WasmCodePosition position) {
Node* stack_slot_dst = graph()->NewNode(
jsgraph()->machine()->StackSlot(MachineRepresentation::kWord64));
Node* stack_slot_src = graph()->NewNode(
@@ -1946,8 +1837,8 @@
// 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);
+ trap_->ZeroCheck32(static_cast<wasm::TrapReason>(trap_zero), call, position);
+ trap_->TrapIfEq32(wasm::kTrapDivUnrepresentable, call, -1, position);
const Operator* load_op = jsgraph()->machine()->Load(result_type);
Node* load =
graph()->NewNode(load_op, stack_slot_dst, jsgraph()->Int32Constant(0),
@@ -1977,7 +1868,8 @@
return call;
}
-Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args) {
+Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args,
+ wasm::WasmCodePosition position) {
const size_t params = sig->parameter_count();
const size_t extra = 2; // effect and control inputs.
const size_t count = 1 + params + extra;
@@ -1993,32 +1885,36 @@
wasm::ModuleEnv::GetWasmCallDescriptor(jsgraph()->zone(), sig);
const Operator* op = jsgraph()->common()->Call(descriptor);
Node* call = graph()->NewNode(op, static_cast<int>(count), args);
+ SetSourcePosition(call, position);
*effect_ = call;
return call;
}
-Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args) {
+Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args,
+ wasm::WasmCodePosition position) {
DCHECK_NULL(args[0]);
// Add code object as constant.
- args[0] = Constant(module_->GetFunctionCode(index));
+ args[0] = HeapConstant(module_->GetFunctionCode(index));
wasm::FunctionSig* sig = module_->GetFunctionSignature(index);
- return BuildWasmCall(sig, args);
+ return BuildWasmCall(sig, args, position);
}
-Node* WasmGraphBuilder::CallImport(uint32_t index, Node** args) {
+Node* WasmGraphBuilder::CallImport(uint32_t index, Node** args,
+ wasm::WasmCodePosition position) {
DCHECK_NULL(args[0]);
// Add code object as constant.
- args[0] = Constant(module_->GetImportCode(index));
+ args[0] = HeapConstant(module_->GetImportCode(index));
wasm::FunctionSig* sig = module_->GetImportSignature(index);
- return BuildWasmCall(sig, args);
+ return BuildWasmCall(sig, args, position);
}
-Node* WasmGraphBuilder::CallIndirect(uint32_t index, Node** args) {
+Node* WasmGraphBuilder::CallIndirect(uint32_t index, Node** args,
+ wasm::WasmCodePosition position) {
DCHECK_NOT_NULL(args[0]);
DCHECK(module_ && module_->instance);
@@ -2033,10 +1929,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(wasm::kTrapFuncInvalid, in_bounds);
+ trap_->AddTrapIfFalse(wasm::kTrapFuncInvalid, in_bounds, position);
} else {
// No function table. Generate a trap and return a constant.
- trap_->AddTrapIfFalse(wasm::kTrapFuncInvalid, Int32Constant(0));
+ trap_->AddTrapIfFalse(wasm::kTrapFuncInvalid, Int32Constant(0), position);
return trap_->GetTrapValue(module_->GetSignature(index));
}
Node* table = FunctionTable();
@@ -2056,7 +1952,7 @@
*effect_, *control_);
Node* sig_match = graph()->NewNode(machine->WordEqual(), load_sig,
jsgraph()->SmiConstant(index));
- trap_->AddTrapIfFalse(wasm::kTrapFuncSigMismatch, sig_match);
+ trap_->AddTrapIfFalse(wasm::kTrapFuncSigMismatch, sig_match, position);
}
// Load code object from the table.
@@ -2071,77 +1967,7 @@
args[0] = load_code;
wasm::FunctionSig* sig = module_->GetSignature(index);
- return BuildWasmCall(sig, args);
-}
-
-
-Node* WasmGraphBuilder::ToJS(Node* node, Node* context, wasm::LocalType type) {
- SimplifiedOperatorBuilder simplified(jsgraph()->zone());
- switch (type) {
- case wasm::kAstI32:
- return graph()->NewNode(simplified.ChangeInt32ToTagged(), node);
- case wasm::kAstI64:
- // TODO(titzer): i64->JS has no good solution right now. Using lower 32
- // bits.
- node =
- graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), node);
- return graph()->NewNode(simplified.ChangeInt32ToTagged(), node);
- case wasm::kAstF32:
- node = graph()->NewNode(jsgraph()->machine()->ChangeFloat32ToFloat64(),
- node);
- return graph()->NewNode(simplified.ChangeFloat64ToTagged(), node);
- case wasm::kAstF64:
- return graph()->NewNode(simplified.ChangeFloat64ToTagged(), node);
- case wasm::kAstStmt:
- return jsgraph()->UndefinedConstant();
- default:
- UNREACHABLE();
- return nullptr;
- }
-}
-
-
-Node* WasmGraphBuilder::FromJS(Node* node, Node* context,
- wasm::LocalType type) {
- // Do a JavaScript ToNumber.
- Node* num =
- graph()->NewNode(jsgraph()->javascript()->ToNumber(), node, context,
- jsgraph()->EmptyFrameState(), *effect_, *control_);
- *control_ = num;
- *effect_ = num;
-
- // Change representation.
- SimplifiedOperatorBuilder simplified(jsgraph()->zone());
- num = graph()->NewNode(simplified.ChangeTaggedToFloat64(), num);
-
- switch (type) {
- case wasm::kAstI32: {
- num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToInt32(
- TruncationMode::kJavaScript),
- num);
- break;
- }
- case wasm::kAstI64:
- // TODO(titzer): JS->i64 has no good solution right now. Using 32 bits.
- num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToInt32(
- TruncationMode::kJavaScript),
- num);
- num = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), num);
- break;
- case wasm::kAstF32:
- num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToFloat32(),
- num);
- break;
- case wasm::kAstF64:
- break;
- case wasm::kAstStmt:
- num = jsgraph()->Int32Constant(0);
- break;
- default:
- UNREACHABLE();
- return nullptr;
- }
- return num;
+ return BuildWasmCall(sig, args, position);
}
Node* WasmGraphBuilder::BuildI32Rol(Node* left, Node* right) {
@@ -2174,31 +2000,404 @@
return Unop(wasm::kExprI32Eqz, node);
}
+Node* WasmGraphBuilder::BuildChangeInt32ToTagged(Node* value) {
+ MachineOperatorBuilder* machine = jsgraph()->machine();
+ CommonOperatorBuilder* common = jsgraph()->common();
+
+ if (machine->Is64()) {
+ return BuildChangeInt32ToSmi(value);
+ }
+
+ Node* add = graph()->NewNode(machine->Int32AddWithOverflow(), value, value);
+
+ Node* ovf = graph()->NewNode(common->Projection(1), add);
+ Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), ovf,
+ graph()->start());
+
+ Node* if_true = graph()->NewNode(common->IfTrue(), branch);
+ Node* vtrue = BuildAllocateHeapNumberWithValue(
+ graph()->NewNode(machine->ChangeInt32ToFloat64(), value), if_true);
+
+ Node* if_false = graph()->NewNode(common->IfFalse(), branch);
+ Node* vfalse = graph()->NewNode(common->Projection(0), add);
+
+ Node* merge = graph()->NewNode(common->Merge(2), if_true, if_false);
+ Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2),
+ vtrue, vfalse, merge);
+ return phi;
+}
+
+Node* WasmGraphBuilder::BuildChangeFloat64ToTagged(Node* value) {
+ MachineOperatorBuilder* machine = jsgraph()->machine();
+ CommonOperatorBuilder* common = jsgraph()->common();
+
+ Node* value32 = graph()->NewNode(machine->RoundFloat64ToInt32(), value);
+ Node* check_same = graph()->NewNode(
+ machine->Float64Equal(), value,
+ graph()->NewNode(machine->ChangeInt32ToFloat64(), value32));
+ Node* branch_same =
+ graph()->NewNode(common->Branch(), check_same, graph()->start());
+
+ Node* if_smi = graph()->NewNode(common->IfTrue(), branch_same);
+ Node* vsmi;
+ Node* if_box = graph()->NewNode(common->IfFalse(), branch_same);
+ Node* vbox;
+
+ // We only need to check for -0 if the {value} can potentially contain -0.
+ Node* check_zero = graph()->NewNode(machine->Word32Equal(), value32,
+ jsgraph()->Int32Constant(0));
+ Node* branch_zero =
+ graph()->NewNode(common->Branch(BranchHint::kFalse), check_zero, if_smi);
+
+ Node* if_zero = graph()->NewNode(common->IfTrue(), branch_zero);
+ Node* if_notzero = graph()->NewNode(common->IfFalse(), branch_zero);
+
+ // In case of 0, we need to check the high bits for the IEEE -0 pattern.
+ Node* check_negative = graph()->NewNode(
+ machine->Int32LessThan(),
+ graph()->NewNode(machine->Float64ExtractHighWord32(), value),
+ jsgraph()->Int32Constant(0));
+ Node* branch_negative = graph()->NewNode(common->Branch(BranchHint::kFalse),
+ check_negative, if_zero);
+
+ Node* if_negative = graph()->NewNode(common->IfTrue(), branch_negative);
+ Node* if_notnegative = graph()->NewNode(common->IfFalse(), branch_negative);
+
+ // We need to create a box for negative 0.
+ if_smi = graph()->NewNode(common->Merge(2), if_notzero, if_notnegative);
+ if_box = graph()->NewNode(common->Merge(2), if_box, if_negative);
+
+ // On 64-bit machines we can just wrap the 32-bit integer in a smi, for 32-bit
+ // machines we need to deal with potential overflow and fallback to boxing.
+ if (machine->Is64()) {
+ vsmi = BuildChangeInt32ToSmi(value32);
+ } else {
+ Node* smi_tag =
+ graph()->NewNode(machine->Int32AddWithOverflow(), value32, value32);
+
+ Node* check_ovf = graph()->NewNode(common->Projection(1), smi_tag);
+ Node* branch_ovf =
+ graph()->NewNode(common->Branch(BranchHint::kFalse), check_ovf, if_smi);
+
+ Node* if_ovf = graph()->NewNode(common->IfTrue(), branch_ovf);
+ if_box = graph()->NewNode(common->Merge(2), if_ovf, if_box);
+
+ if_smi = graph()->NewNode(common->IfFalse(), branch_ovf);
+ vsmi = graph()->NewNode(common->Projection(0), smi_tag);
+ }
+
+ // Allocate the box for the {value}.
+ vbox = BuildAllocateHeapNumberWithValue(value, if_box);
+
+ Node* control = graph()->NewNode(common->Merge(2), if_smi, if_box);
+ value = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2), vsmi,
+ vbox, control);
+ return value;
+}
+
+Node* WasmGraphBuilder::ToJS(Node* node, Node* context, wasm::LocalType type) {
+ switch (type) {
+ case wasm::kAstI32:
+ return BuildChangeInt32ToTagged(node);
+ case wasm::kAstI64:
+ // TODO(titzer): i64->JS has no good solution right now. Using lower 32
+ // bits.
+ if (jsgraph()->machine()->Is64()) {
+ // On 32 bit platforms we do not have to do the truncation because the
+ // node we get in as a parameter only contains the low word anyways.
+ node = graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(),
+ node);
+ }
+ return BuildChangeInt32ToTagged(node);
+ case wasm::kAstF32:
+ node = graph()->NewNode(jsgraph()->machine()->ChangeFloat32ToFloat64(),
+ node);
+ return BuildChangeFloat64ToTagged(node);
+ case wasm::kAstF64:
+ return BuildChangeFloat64ToTagged(node);
+ case wasm::kAstStmt:
+ return jsgraph()->UndefinedConstant();
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+}
+
+Node* WasmGraphBuilder::BuildJavaScriptToNumber(Node* node, Node* context,
+ Node* effect, Node* control) {
+ Callable callable = CodeFactory::ToNumber(jsgraph()->isolate());
+ CallDescriptor* desc = Linkage::GetStubCallDescriptor(
+ jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0,
+ CallDescriptor::kNoFlags, Operator::kNoProperties);
+ Node* stub_code = jsgraph()->HeapConstant(callable.code());
+
+ Node* result = graph()->NewNode(jsgraph()->common()->Call(desc), stub_code,
+ node, context, effect, control);
+
+ *control_ = result;
+ *effect_ = result;
+
+ return result;
+}
+
+bool CanCover(Node* value, IrOpcode::Value opcode) {
+ if (value->opcode() != opcode) return false;
+ bool first = true;
+ for (Edge const edge : value->use_edges()) {
+ if (NodeProperties::IsControlEdge(edge)) continue;
+ if (NodeProperties::IsEffectEdge(edge)) continue;
+ DCHECK(NodeProperties::IsValueEdge(edge));
+ if (!first) return false;
+ first = false;
+ }
+ return true;
+}
+
+Node* WasmGraphBuilder::BuildChangeTaggedToFloat64(Node* value) {
+ MachineOperatorBuilder* machine = jsgraph()->machine();
+ CommonOperatorBuilder* common = jsgraph()->common();
+
+ if (CanCover(value, IrOpcode::kJSToNumber)) {
+ // ChangeTaggedToFloat64(JSToNumber(x)) =>
+ // if IsSmi(x) then ChangeSmiToFloat64(x)
+ // else let y = JSToNumber(x) in
+ // if IsSmi(y) then ChangeSmiToFloat64(y)
+ // else BuildLoadHeapNumberValue(y)
+ Node* object = NodeProperties::GetValueInput(value, 0);
+ Node* context = NodeProperties::GetContextInput(value);
+ Node* frame_state = NodeProperties::GetFrameStateInput(value, 0);
+ Node* effect = NodeProperties::GetEffectInput(value);
+ Node* control = NodeProperties::GetControlInput(value);
+
+ const Operator* merge_op = common->Merge(2);
+ const Operator* ephi_op = common->EffectPhi(2);
+ const Operator* phi_op = common->Phi(MachineRepresentation::kFloat64, 2);
+
+ Node* check1 = BuildTestNotSmi(object);
+ Node* branch1 =
+ graph()->NewNode(common->Branch(BranchHint::kFalse), check1, control);
+
+ Node* if_true1 = graph()->NewNode(common->IfTrue(), branch1);
+ Node* vtrue1 = graph()->NewNode(value->op(), object, context, frame_state,
+ effect, if_true1);
+ Node* etrue1 = vtrue1;
+
+ Node* check2 = BuildTestNotSmi(vtrue1);
+ Node* branch2 = graph()->NewNode(common->Branch(), check2, if_true1);
+
+ Node* if_true2 = graph()->NewNode(common->IfTrue(), branch2);
+ Node* vtrue2 = BuildLoadHeapNumberValue(vtrue1, if_true2);
+
+ Node* if_false2 = graph()->NewNode(common->IfFalse(), branch2);
+ Node* vfalse2 = BuildChangeSmiToFloat64(vtrue1);
+
+ if_true1 = graph()->NewNode(merge_op, if_true2, if_false2);
+ vtrue1 = graph()->NewNode(phi_op, vtrue2, vfalse2, if_true1);
+
+ Node* if_false1 = graph()->NewNode(common->IfFalse(), branch1);
+ Node* vfalse1 = BuildChangeSmiToFloat64(object);
+ Node* efalse1 = effect;
+
+ Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1);
+ Node* ephi1 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1);
+ Node* phi1 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1);
+
+ // Wire the new diamond into the graph, {JSToNumber} can still throw.
+ NodeProperties::ReplaceUses(value, phi1, ephi1, etrue1, etrue1);
+
+ // TODO(mstarzinger): This iteration cuts out the IfSuccess projection from
+ // the node and places it inside the diamond. Come up with a helper method!
+ for (Node* use : etrue1->uses()) {
+ if (use->opcode() == IrOpcode::kIfSuccess) {
+ use->ReplaceUses(merge1);
+ NodeProperties::ReplaceControlInput(branch2, use);
+ }
+ }
+ return phi1;
+ }
+
+ Node* check = BuildTestNotSmi(value);
+ Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), check,
+ graph()->start());
+
+ Node* if_not_smi = graph()->NewNode(common->IfTrue(), branch);
+
+ Node* vnot_smi;
+ Node* check_undefined = graph()->NewNode(machine->WordEqual(), value,
+ jsgraph()->UndefinedConstant());
+ Node* branch_undefined = graph()->NewNode(common->Branch(BranchHint::kFalse),
+ check_undefined, if_not_smi);
+
+ Node* if_undefined = graph()->NewNode(common->IfTrue(), branch_undefined);
+ Node* vundefined =
+ jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
+
+ Node* if_not_undefined =
+ graph()->NewNode(common->IfFalse(), branch_undefined);
+ Node* vheap_number = BuildLoadHeapNumberValue(value, if_not_undefined);
+
+ if_not_smi =
+ graph()->NewNode(common->Merge(2), if_undefined, if_not_undefined);
+ vnot_smi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2),
+ vundefined, vheap_number, if_not_smi);
+
+ Node* if_smi = graph()->NewNode(common->IfFalse(), branch);
+ Node* vfrom_smi = BuildChangeSmiToFloat64(value);
+
+ Node* merge = graph()->NewNode(common->Merge(2), if_not_smi, if_smi);
+ Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2),
+ vnot_smi, vfrom_smi, merge);
+
+ return phi;
+}
+
+Node* WasmGraphBuilder::FromJS(Node* node, Node* context,
+ wasm::LocalType type) {
+ // Do a JavaScript ToNumber.
+ Node* num = BuildJavaScriptToNumber(node, context, *effect_, *control_);
+
+ // Change representation.
+ SimplifiedOperatorBuilder simplified(jsgraph()->zone());
+ num = BuildChangeTaggedToFloat64(num);
+
+ switch (type) {
+ case wasm::kAstI32: {
+ num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToWord32(),
+ num);
+ break;
+ }
+ case wasm::kAstI64:
+ // TODO(titzer): JS->i64 has no good solution right now. Using 32 bits.
+ num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToWord32(),
+ num);
+ if (jsgraph()->machine()->Is64()) {
+ // We cannot change an int32 to an int64 on a 32 bit platform. Instead
+ // we will split the parameter node later.
+ num = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), num);
+ }
+ break;
+ case wasm::kAstF32:
+ num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToFloat32(),
+ num);
+ break;
+ case wasm::kAstF64:
+ break;
+ case wasm::kAstStmt:
+ num = jsgraph()->Int32Constant(0);
+ break;
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ return num;
+}
+
+Node* WasmGraphBuilder::BuildChangeInt32ToSmi(Node* value) {
+ if (jsgraph()->machine()->Is64()) {
+ value = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), value);
+ }
+ return graph()->NewNode(jsgraph()->machine()->WordShl(), value,
+ BuildSmiShiftBitsConstant());
+}
+
+Node* WasmGraphBuilder::BuildChangeSmiToInt32(Node* value) {
+ value = graph()->NewNode(jsgraph()->machine()->WordSar(), value,
+ BuildSmiShiftBitsConstant());
+ if (jsgraph()->machine()->Is64()) {
+ value =
+ graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), value);
+ }
+ return value;
+}
+
+Node* WasmGraphBuilder::BuildChangeSmiToFloat64(Node* value) {
+ return graph()->NewNode(jsgraph()->machine()->ChangeInt32ToFloat64(),
+ BuildChangeSmiToInt32(value));
+}
+
+Node* WasmGraphBuilder::BuildTestNotSmi(Node* value) {
+ STATIC_ASSERT(kSmiTag == 0);
+ STATIC_ASSERT(kSmiTagMask == 1);
+ return graph()->NewNode(jsgraph()->machine()->WordAnd(), value,
+ jsgraph()->IntPtrConstant(kSmiTagMask));
+}
+
+Node* WasmGraphBuilder::BuildSmiShiftBitsConstant() {
+ return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize);
+}
+
+Node* WasmGraphBuilder::BuildAllocateHeapNumberWithValue(Node* value,
+ Node* control) {
+ MachineOperatorBuilder* machine = jsgraph()->machine();
+ CommonOperatorBuilder* common = jsgraph()->common();
+ // The AllocateHeapNumberStub does not use the context, so we can safely pass
+ // in Smi zero here.
+ Callable callable = CodeFactory::AllocateHeapNumber(jsgraph()->isolate());
+ Node* target = jsgraph()->HeapConstant(callable.code());
+ Node* context = jsgraph()->NoContextConstant();
+ Node* effect = graph()->NewNode(common->BeginRegion(), graph()->start());
+ if (!allocate_heap_number_operator_.is_set()) {
+ CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
+ jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0,
+ CallDescriptor::kNoFlags, Operator::kNoThrow);
+ allocate_heap_number_operator_.set(common->Call(descriptor));
+ }
+ Node* heap_number = graph()->NewNode(allocate_heap_number_operator_.get(),
+ target, context, effect, control);
+ Node* store =
+ graph()->NewNode(machine->Store(StoreRepresentation(
+ MachineRepresentation::kFloat64, kNoWriteBarrier)),
+ heap_number, BuildHeapNumberValueIndexConstant(), value,
+ heap_number, control);
+ return graph()->NewNode(common->FinishRegion(), heap_number, store);
+}
+
+Node* WasmGraphBuilder::BuildLoadHeapNumberValue(Node* value, Node* control) {
+ return graph()->NewNode(jsgraph()->machine()->Load(MachineType::Float64()),
+ value, BuildHeapNumberValueIndexConstant(),
+ graph()->start(), control);
+}
+
+Node* WasmGraphBuilder::BuildHeapNumberValueIndexConstant() {
+ return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag);
+}
void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code,
wasm::FunctionSig* sig) {
- int params = static_cast<int>(sig->parameter_count());
- int count = params + 3;
+ int wasm_count = static_cast<int>(sig->parameter_count());
+ int param_count;
+ if (jsgraph()->machine()->Is64()) {
+ param_count = static_cast<int>(sig->parameter_count());
+ } else {
+ param_count = Int64Lowering::GetParameterCountAfterLowering(sig);
+ }
+ int count = param_count + 3;
Node** args = Buffer(count);
// Build the start and the JS parameter nodes.
- Node* start = Start(params + 5);
+ Node* start = Start(param_count + 5);
*control_ = start;
*effect_ = start;
// Create the context parameter
Node* context = graph()->NewNode(
jsgraph()->common()->Parameter(
- Linkage::GetJSCallContextParamIndex(params + 1), "%context"),
+ Linkage::GetJSCallContextParamIndex(wasm_count + 1), "%context"),
graph()->start());
int pos = 0;
- args[pos++] = Constant(wasm_code);
+ args[pos++] = HeapConstant(wasm_code);
// Convert JS parameters to WASM numbers.
- for (int i = 0; i < params; i++) {
+ for (int i = 0; i < wasm_count; i++) {
Node* param =
graph()->NewNode(jsgraph()->common()->Parameter(i + 1), start);
- args[pos++] = FromJS(param, context, sig->GetParam(i));
+ Node* wasm_param = FromJS(param, context, sig->GetParam(i));
+ args[pos++] = wasm_param;
+ if (jsgraph()->machine()->Is32() && sig->GetParam(i) == wasm::kAstI64) {
+ // We make up the high word with SAR to get the proper sign extension.
+ args[pos++] = graph()->NewNode(jsgraph()->machine()->Word32Sar(),
+ wasm_param, jsgraph()->Int32Constant(31));
+ }
}
args[pos++] = *effect_;
@@ -2207,9 +2406,18 @@
// Call the WASM code.
CallDescriptor* desc =
wasm::ModuleEnv::GetWasmCallDescriptor(jsgraph()->zone(), sig);
+ if (jsgraph()->machine()->Is32()) {
+ desc = wasm::ModuleEnv::GetI32WasmCallDescriptor(jsgraph()->zone(), desc);
+ }
Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), count, args);
+ Node* retval = call;
+ if (jsgraph()->machine()->Is32() && sig->return_count() > 0 &&
+ sig->GetReturn(0) == wasm::kAstI64) {
+ // The return values comes as two values, we pick the low word.
+ retval = graph()->NewNode(jsgraph()->common()->Projection(0), retval);
+ }
Node* jsval =
- ToJS(call, context,
+ ToJS(retval, context,
sig->return_count() == 0 ? wasm::kAstStmt : sig->GetReturn());
Node* ret =
graph()->NewNode(jsgraph()->common()->Return(), jsval, call, start);
@@ -2217,20 +2425,25 @@
MergeControlToEnd(jsgraph(), ret);
}
-
void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSFunction> function,
wasm::FunctionSig* sig) {
int js_count = function->shared()->internal_formal_parameter_count();
int wasm_count = static_cast<int>(sig->parameter_count());
+ int param_count;
+ if (jsgraph()->machine()->Is64()) {
+ param_count = wasm_count;
+ } else {
+ param_count = Int64Lowering::GetParameterCountAfterLowering(sig);
+ }
// Build the start and the parameter nodes.
Isolate* isolate = jsgraph()->isolate();
CallDescriptor* desc;
- Node* start = Start(wasm_count + 3);
+ Node* start = Start(param_count + 3);
*effect_ = start;
*control_ = start;
// JS context is the last parameter.
- Node* context = Constant(Handle<Context>(function->context(), isolate));
+ Node* context = HeapConstant(Handle<Context>(function->context(), isolate));
Node** args = Buffer(wasm_count + 7);
bool arg_count_before_args = false;
@@ -2262,9 +2475,15 @@
args[pos++] = jsgraph()->Constant(global);
// Convert WASM numbers to JS values.
+ int param_index = 0;
for (int i = 0; i < wasm_count; i++) {
- Node* param = graph()->NewNode(jsgraph()->common()->Parameter(i), start);
+ Node* param =
+ graph()->NewNode(jsgraph()->common()->Parameter(param_index++), start);
args[pos++] = ToJS(param, context, sig->GetParam(i));
+ if (jsgraph()->machine()->Is32() && sig->GetParam(i) == wasm::kAstI64) {
+ // On 32 bit platforms we have to skip the high word of int64 parameters.
+ param_index++;
+ }
}
if (add_new_target_undefined) {
@@ -2281,30 +2500,39 @@
Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), pos, args);
// Convert the return value back.
+ Node* ret;
Node* val =
FromJS(call, context,
sig->return_count() == 0 ? wasm::kAstStmt : sig->GetReturn());
- Node* ret = graph()->NewNode(jsgraph()->common()->Return(), val, call, start);
+ if (jsgraph()->machine()->Is32() && sig->return_count() > 0 &&
+ sig->GetReturn() == wasm::kAstI64) {
+ ret = graph()->NewNode(jsgraph()->common()->Return(), val,
+ graph()->NewNode(jsgraph()->machine()->Word32Sar(),
+ val, jsgraph()->Int32Constant(31)),
+ call, start);
+ } else {
+ ret = graph()->NewNode(jsgraph()->common()->Return(), val, call, start);
+ }
MergeControlToEnd(jsgraph(), ret);
}
-
Node* WasmGraphBuilder::MemBuffer(uint32_t offset) {
DCHECK(module_ && module_->instance);
if (offset == 0) {
if (!mem_buffer_) {
- mem_buffer_ = jsgraph()->IntPtrConstant(
- reinterpret_cast<uintptr_t>(module_->instance->mem_start));
+ mem_buffer_ = jsgraph()->RelocatableIntPtrConstant(
+ reinterpret_cast<uintptr_t>(module_->instance->mem_start),
+ RelocInfo::WASM_MEMORY_REFERENCE);
}
return mem_buffer_;
} else {
- return jsgraph()->IntPtrConstant(
- reinterpret_cast<uintptr_t>(module_->instance->mem_start + offset));
+ return jsgraph()->RelocatableIntPtrConstant(
+ reinterpret_cast<uintptr_t>(module_->instance->mem_start + offset),
+ RelocInfo::WASM_MEMORY_REFERENCE);
}
}
-
Node* WasmGraphBuilder::MemSize(uint32_t offset) {
DCHECK(module_ && module_->instance);
uint32_t size = static_cast<uint32_t>(module_->instance->mem_size);
@@ -2316,17 +2544,15 @@
}
}
-
Node* WasmGraphBuilder::FunctionTable() {
DCHECK(module_ && module_->instance &&
!module_->instance->function_table.is_null());
if (!function_table_) {
- function_table_ = jsgraph()->Constant(module_->instance->function_table);
+ function_table_ = HeapConstant(module_->instance->function_table);
}
return function_table_;
}
-
Node* WasmGraphBuilder::LoadGlobal(uint32_t index) {
DCHECK(module_ && module_->instance && module_->instance->globals_start);
MachineType mem_type = module_->GetGlobalType(index);
@@ -2340,7 +2566,6 @@
return node;
}
-
Node* WasmGraphBuilder::StoreGlobal(uint32_t index, Node* val) {
DCHECK(module_ && module_->instance && module_->instance->globals_start);
MachineType mem_type = module_->GetGlobalType(index);
@@ -2355,46 +2580,48 @@
return node;
}
-
void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index,
- uint32_t offset) {
- // TODO(turbofan): fold bounds checks for constant indexes.
+ uint32_t offset,
+ wasm::WasmCodePosition position) {
DCHECK(module_ && module_->instance);
size_t size = module_->instance->mem_size;
byte memsize = wasm::WasmOpcodes::MemSize(memtype);
- Node* cond;
+
if (offset >= size || (static_cast<uint64_t>(offset) + memsize) > size) {
- // The access will always throw.
- cond = jsgraph()->Int32Constant(0);
- } else {
- // Check against the limit.
- size_t limit = size - offset - memsize;
- CHECK(limit <= kMaxUInt32);
- cond = graph()->NewNode(
- jsgraph()->machine()->Uint32LessThanOrEqual(), index,
- jsgraph()->Int32Constant(static_cast<uint32_t>(limit)));
+ // The access will always throw (unless memory is grown).
+ Node* cond = jsgraph()->Int32Constant(0);
+ trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position);
+ return;
}
- trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond);
+ // Check against the effective size.
+ size_t effective_size = size - offset - memsize;
+ CHECK(effective_size <= kMaxUInt32);
+
+ Uint32Matcher m(index);
+ if (m.HasValue()) {
+ uint32_t value = m.Value();
+ if (value <= effective_size) {
+ // The bounds check will always succeed.
+ return;
+ }
+ }
+
+ Node* cond = graph()->NewNode(
+ jsgraph()->machine()->Uint32LessThanOrEqual(), index,
+ jsgraph()->Int32Constant(static_cast<uint32_t>(effective_size)));
+
+ trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position);
}
-
Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype,
- Node* index, uint32_t offset) {
+ Node* index, uint32_t offset,
+ wasm::WasmCodePosition position) {
Node* load;
-
- 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);
- load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_,
- *control_);
- } else {
- // WASM semantics throw on OOB. Introduce explicit bounds check.
- BoundsCheckMem(memtype, index, offset);
- load = graph()->NewNode(jsgraph()->machine()->Load(memtype),
- MemBuffer(offset), index, *effect_, *control_);
- }
+ // WASM semantics throw on OOB. Introduce explicit bounds check.
+ BoundsCheckMem(memtype, index, offset, position);
+ load = graph()->NewNode(jsgraph()->machine()->Load(memtype),
+ MemBuffer(offset), index, *effect_, *control_);
*effect_ = load;
@@ -2414,41 +2641,50 @@
return load;
}
-
Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
- uint32_t offset, Node* val) {
+ uint32_t offset, Node* val,
+ wasm::WasmCodePosition position) {
Node* store;
- if (module_ && module_->asm_js()) {
- // asm.js semantics use CheckedStore (i.e. ignore OOB writes).
- DCHECK_EQ(0, offset);
- const Operator* op =
- jsgraph()->machine()->CheckedStore(memtype.representation());
- store = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), val, *effect_,
- *control_);
- } else {
- // WASM semantics throw on OOB. Introduce explicit bounds check.
- BoundsCheckMem(memtype, index, offset);
- StoreRepresentation rep(memtype.representation(), kNoWriteBarrier);
- store =
- graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset),
- index, val, *effect_, *control_);
- }
+ // WASM semantics throw on OOB. Introduce explicit bounds check.
+ BoundsCheckMem(memtype, index, offset, position);
+ StoreRepresentation rep(memtype.representation(), kNoWriteBarrier);
+ store = graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset),
+ index, val, *effect_, *control_);
*effect_ = store;
return store;
}
+Node* WasmGraphBuilder::BuildAsmjsLoadMem(MachineType type, Node* index) {
+ // TODO(turbofan): fold bounds checks for constant asm.js loads.
+ // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish).
+ const Operator* op = jsgraph()->machine()->CheckedLoad(type);
+ Node* load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_,
+ *control_);
+ *effect_ = load;
+ return load;
+}
+
+Node* WasmGraphBuilder::BuildAsmjsStoreMem(MachineType type, Node* index,
+ Node* val) {
+ // TODO(turbofan): fold bounds checks for constant asm.js stores.
+ // asm.js semantics use CheckedStore (i.e. ignore OOB writes).
+ const Operator* op =
+ jsgraph()->machine()->CheckedStore(type.representation());
+ Node* store = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), val,
+ *effect_, *control_);
+ *effect_ = store;
+ return val;
+}
void WasmGraphBuilder::PrintDebugName(Node* node) {
PrintF("#%d:%s", node->id(), node->op()->mnemonic());
}
-
Node* WasmGraphBuilder::String(const char* string) {
return jsgraph()->Constant(
jsgraph()->isolate()->factory()->NewStringFromAsciiChecked(string));
}
-
Graph* WasmGraphBuilder::graph() { return jsgraph()->graph(); }
void WasmGraphBuilder::Int64LoweringForTesting() {
@@ -2460,6 +2696,14 @@
}
}
+void WasmGraphBuilder::SetSourcePosition(Node* node,
+ wasm::WasmCodePosition position) {
+ DCHECK_NE(position, wasm::kNoCodePosition);
+ compiler::SourcePosition pos(position);
+ if (source_position_table_)
+ source_position_table_->SetSourcePosition(node, pos);
+}
+
static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
CompilationInfo* info,
const char* message, uint32_t index,
@@ -2468,8 +2712,8 @@
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.length,
- func_name.name);
+ SNPrintF(buffer, "%s#%d:%.*s", message, index, func_name.length(),
+ func_name.start());
Handle<String> name_str =
isolate->factory()->NewStringFromAsciiChecked(buffer.start());
Handle<String> script_str =
@@ -2478,7 +2722,7 @@
Handle<SharedFunctionInfo> shared =
isolate->factory()->NewSharedFunctionInfo(name_str, code, false);
PROFILE(isolate, CodeCreateEvent(tag, AbstractCode::cast(*code), *shared,
- info, *script_str, 0, 0));
+ *script_str, 0, 0));
}
}
@@ -2506,9 +2750,8 @@
Zone zone(isolate->allocator());
Graph graph(&zone);
CommonOperatorBuilder common(&zone);
- JSOperatorBuilder javascript(&zone);
MachineOperatorBuilder machine(&zone);
- JSGraph jsgraph(isolate, &graph, &common, &javascript, nullptr, &machine);
+ JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
Node* control = nullptr;
Node* effect = nullptr;
@@ -2523,20 +2766,6 @@
// Run the compilation pipeline.
//----------------------------------------------------------------------------
{
- // Changes lowering requires types.
- Typer typer(isolate, &graph);
- NodeVector roots(&zone);
- jsgraph.GetCachedNodes(&roots);
- typer.Run(roots);
-
- // Run generic and change lowering.
- JSGenericLowering generic(true, &jsgraph);
- ChangeLowering changes(&jsgraph);
- GraphReducer graph_reducer(&zone, &graph, jsgraph.Dead());
- graph_reducer.AddReducer(&changes);
- graph_reducer.AddReducer(&generic);
- graph_reducer.ReduceGraph();
-
if (FLAG_trace_turbo_graph) { // Simple textual RPO.
OFStream os(stdout);
os << "-- Graph after change lowering -- " << std::endl;
@@ -2555,19 +2784,19 @@
#else
FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
#endif
- const char* func_name = "js-to-wasm";
+ Vector<const char> func_name = ArrayVector("js-to-wasm");
static unsigned id = 0;
Vector<char> buffer;
if (debugging) {
buffer = Vector<char>::New(128);
- SNPrintF(buffer, "js-to-wasm#%d", id);
- func_name = buffer.start();
+ int chars = SNPrintF(buffer, "js-to-wasm#%d", id);
+ func_name = Vector<const char>::cast(buffer.SubVector(0, chars));
}
CompilationInfo info(func_name, isolate, &zone, flags);
Handle<Code> code =
- Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr);
+ Pipeline::GenerateCodeForTesting(&info, incoming, &graph);
#ifdef ENABLE_DISASSEMBLER
if (FLAG_print_opt_code && !code.is_null()) {
OFStream os(stdout);
@@ -2598,9 +2827,8 @@
Zone zone(isolate->allocator());
Graph graph(&zone);
CommonOperatorBuilder common(&zone);
- JSOperatorBuilder javascript(&zone);
MachineOperatorBuilder machine(&zone);
- JSGraph jsgraph(isolate, &graph, &common, &javascript, nullptr, &machine);
+ JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
Node* control = nullptr;
Node* effect = nullptr;
@@ -2613,20 +2841,6 @@
Handle<Code> code = Handle<Code>::null();
{
- // Changes lowering requires types.
- Typer typer(isolate, &graph);
- NodeVector roots(&zone);
- jsgraph.GetCachedNodes(&roots);
- typer.Run(roots);
-
- // Run generic and change lowering.
- JSGenericLowering generic(true, &jsgraph);
- ChangeLowering changes(&jsgraph);
- GraphReducer graph_reducer(&zone, &graph, jsgraph.Dead());
- graph_reducer.AddReducer(&changes);
- graph_reducer.AddReducer(&generic);
- graph_reducer.ReduceGraph();
-
if (FLAG_trace_turbo_graph) { // Simple textual RPO.
OFStream os(stdout);
os << "-- Graph after change lowering -- " << std::endl;
@@ -2636,6 +2850,9 @@
// Schedule and compile to machine code.
CallDescriptor* incoming =
wasm::ModuleEnv::GetWasmCallDescriptor(&zone, sig);
+ if (machine.Is32()) {
+ incoming = wasm::ModuleEnv::GetI32WasmCallDescriptor(&zone, incoming);
+ }
Code::Flags flags = Code::ComputeFlags(Code::WASM_TO_JS_FUNCTION);
bool debugging =
#if DEBUG
@@ -2643,13 +2860,13 @@
#else
FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
#endif
- const char* func_name = "wasm-to-js";
+ Vector<const char> func_name = ArrayVector("wasm-to-js");
static unsigned id = 0;
Vector<char> buffer;
if (debugging) {
buffer = Vector<char>::New(128);
- SNPrintF(buffer, "wasm-to-js#%d", id);
- func_name = buffer.start();
+ int chars = SNPrintF(buffer, "wasm-to-js#%d", id);
+ func_name = Vector<const char>::cast(buffer.SubVector(0, chars));
}
CompilationInfo info(func_name, isolate, &zone, flags);
@@ -2670,40 +2887,34 @@
return code;
}
-
-// Helper function to compile a single function.
-Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
- wasm::ModuleEnv* module_env,
- const wasm::WasmFunction& function) {
- if (FLAG_trace_wasm_compiler) {
- OFStream os(stdout);
- os << "Compiling WASM function "
- << wasm::WasmFunctionName(&function, module_env) << std::endl;
- os << std::endl;
- }
-
- double decode_ms = 0;
+std::pair<JSGraph*, SourcePositionTable*> BuildGraphForWasmFunction(
+ JSGraph* jsgraph, wasm::ErrorThrower* thrower, Isolate* isolate,
+ wasm::ModuleEnv*& module_env, const wasm::WasmFunction* function,
+ double* decode_ms) {
base::ElapsedTimer decode_timer;
if (FLAG_trace_wasm_decode_time) {
decode_timer.Start();
}
-
// Create a TF graph during decoding.
- Zone zone(isolate->allocator());
- Graph graph(&zone);
- CommonOperatorBuilder common(&zone);
- MachineOperatorBuilder machine(
- &zone, MachineType::PointerRepresentation(),
- InstructionSelector::SupportedMachineOperatorFlags());
- JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
- WasmGraphBuilder builder(&zone, &jsgraph, function.sig);
+ Graph* graph = jsgraph->graph();
+ CommonOperatorBuilder* common = jsgraph->common();
+ MachineOperatorBuilder* machine = jsgraph->machine();
+ SourcePositionTable* source_position_table =
+ new (jsgraph->zone()) SourcePositionTable(graph);
+ WasmGraphBuilder builder(jsgraph->zone(), jsgraph, function->sig,
+ source_position_table);
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};
+ 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 (machine->Is32()) {
+ Int64Lowering r(graph, machine, common, jsgraph->zone(), function->sig);
+ r.LowerGraph();
+ }
+
if (result.failed()) {
if (FLAG_trace_wasm_compiler) {
OFStream os(stdout);
@@ -2711,76 +2922,198 @@
}
// Add the function as another context for the exception
ScopedVector<char> buffer(128);
- wasm::WasmName name =
- module_env->module->GetName(function.name_offset, function.name_length);
+ 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();
+ function->func_index, name.length(), name.start());
+ thrower->Failed(buffer.start(), result);
+ return std::make_pair(nullptr, nullptr);
}
-
- int index = static_cast<int>(function.func_index);
+ 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();
+ *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 (machine.Is32()) {
- descriptor = module_env->GetI32WasmCallDescriptor(&zone, descriptor);
- }
- Code::Flags flags = Code::ComputeFlags(Code::WASM_FUNCTION);
- // add flags here if a meaningful name is helpful for debugging.
- bool debugging =
-#if DEBUG
- true;
-#else
- FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
-#endif
- const char* func_name = "wasm";
- Vector<char> buffer;
- if (debugging) {
- buffer = Vector<char>::New(128);
- 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);
-
- Handle<Code> code =
- Pipeline::GenerateCodeForTesting(&info, descriptor, &graph);
- if (debugging) {
- buffer.Dispose();
- }
- if (!code.is_null()) {
- 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;
+ return std::make_pair(jsgraph, source_position_table);
}
+class WasmCompilationUnit {
+ public:
+ WasmCompilationUnit(wasm::ErrorThrower* thrower, Isolate* isolate,
+ wasm::ModuleEnv* module_env,
+ const wasm::WasmFunction* function, uint32_t index)
+ : thrower_(thrower),
+ isolate_(isolate),
+ module_env_(module_env),
+ function_(function),
+ graph_zone_(new Zone(isolate->allocator())),
+ jsgraph_(new (graph_zone()) JSGraph(
+ isolate, new (graph_zone()) Graph(graph_zone()),
+ new (graph_zone()) CommonOperatorBuilder(graph_zone()), nullptr,
+ nullptr,
+ new (graph_zone()) MachineOperatorBuilder(
+ graph_zone(), MachineType::PointerRepresentation(),
+ InstructionSelector::SupportedMachineOperatorFlags()))),
+ compilation_zone_(isolate->allocator()),
+ info_(function->name_length != 0
+ ? module_env->module->GetNameOrNull(function->name_offset,
+ function->name_length)
+ : ArrayVector("wasm"),
+ isolate, &compilation_zone_,
+ Code::ComputeFlags(Code::WASM_FUNCTION)),
+ job_(),
+ index_(index),
+ ok_(true) {
+ // Create and cache this node in the main thread.
+ jsgraph_->CEntryStubConstant(1);
+ }
+
+ Zone* graph_zone() { return graph_zone_.get(); }
+
+ void ExecuteCompilation() {
+ // TODO(ahaas): The counters are not thread-safe at the moment.
+ // HistogramTimerScope wasm_compile_function_time_scope(
+ // isolate_->counters()->wasm_compile_function_time());
+ if (FLAG_trace_wasm_compiler) {
+ OFStream os(stdout);
+ os << "Compiling WASM function "
+ << wasm::WasmFunctionName(function_, module_env_) << std::endl;
+ os << std::endl;
+ }
+
+ double decode_ms = 0;
+ size_t node_count = 0;
+
+ base::SmartPointer<Zone> graph_zone(graph_zone_.Detach());
+ std::pair<JSGraph*, SourcePositionTable*> graph_result =
+ BuildGraphForWasmFunction(jsgraph_, thrower_, isolate_, module_env_,
+ function_, &decode_ms);
+ JSGraph* jsgraph = graph_result.first;
+ SourcePositionTable* source_positions = graph_result.second;
+
+ if (jsgraph == nullptr) {
+ ok_ = false;
+ return;
+ }
+
+ base::ElapsedTimer pipeline_timer;
+ if (FLAG_trace_wasm_decode_time) {
+ node_count = jsgraph->graph()->NodeCount();
+ pipeline_timer.Start();
+ }
+
+ // Run the compiler pipeline to generate machine code.
+ CallDescriptor* descriptor = wasm::ModuleEnv::GetWasmCallDescriptor(
+ &compilation_zone_, function_->sig);
+ if (jsgraph->machine()->Is32()) {
+ descriptor =
+ module_env_->GetI32WasmCallDescriptor(&compilation_zone_, descriptor);
+ }
+ job_.Reset(Pipeline::NewWasmCompilationJob(&info_, jsgraph->graph(),
+ descriptor, source_positions));
+ ok_ = job_->OptimizeGraph() == CompilationJob::SUCCEEDED;
+ // TODO(bradnelson): Improve histogram handling of size_t.
+ // TODO(ahaas): The counters are not thread-safe at the moment.
+ // isolate_->counters()->wasm_compile_function_peak_memory_bytes()
+ // ->AddSample(
+ // static_cast<int>(jsgraph->graph()->zone()->allocation_size()));
+
+ if (FLAG_trace_wasm_decode_time) {
+ double pipeline_ms = pipeline_timer.Elapsed().InMillisecondsF();
+ PrintF(
+ "wasm-compilation phase 1 ok: %d bytes, %0.3f ms decode, %zu nodes, "
+ "%0.3f ms pipeline\n",
+ static_cast<int>(function_->code_end_offset -
+ function_->code_start_offset),
+ decode_ms, node_count, pipeline_ms);
+ }
+ }
+
+ Handle<Code> FinishCompilation() {
+ if (!ok_) {
+ return Handle<Code>::null();
+ }
+ if (job_->GenerateCode() != CompilationJob::SUCCEEDED) {
+ return Handle<Code>::null();
+ }
+ base::ElapsedTimer compile_timer;
+ if (FLAG_trace_wasm_decode_time) {
+ compile_timer.Start();
+ }
+ Handle<Code> code = info_.code();
+ DCHECK(!code.is_null());
+ DCHECK(code->deoptimization_data() == nullptr ||
+ code->deoptimization_data()->length() == 0);
+ Handle<FixedArray> deopt_data =
+ isolate_->factory()->NewFixedArray(2, TENURED);
+ if (!module_env_->instance->js_object.is_null()) {
+ deopt_data->set(0, *module_env_->instance->js_object);
+ }
+ deopt_data->set(1, Smi::FromInt(function_->func_index));
+ deopt_data->set_length(2);
+ code->set_deoptimization_data(*deopt_data);
+
+ 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-code-generation ok: %d bytes, %0.3f ms code generation\n",
+ static_cast<int>(function_->code_end_offset -
+ function_->code_start_offset),
+ compile_ms);
+ }
+
+ return code;
+ }
+
+ wasm::ErrorThrower* thrower_;
+ Isolate* isolate_;
+ wasm::ModuleEnv* module_env_;
+ const wasm::WasmFunction* function_;
+ // The graph zone is deallocated at the end of ExecuteCompilation.
+ base::SmartPointer<Zone> graph_zone_;
+ JSGraph* jsgraph_;
+ Zone compilation_zone_;
+ CompilationInfo info_;
+ base::SmartPointer<CompilationJob> job_;
+ uint32_t index_;
+ bool ok_;
+};
+
+WasmCompilationUnit* CreateWasmCompilationUnit(
+ wasm::ErrorThrower* thrower, Isolate* isolate, wasm::ModuleEnv* module_env,
+ const wasm::WasmFunction* function, uint32_t index) {
+ return new WasmCompilationUnit(thrower, isolate, module_env, function, index);
+}
+
+void ExecuteCompilation(WasmCompilationUnit* unit) {
+ unit->ExecuteCompilation();
+}
+
+uint32_t GetIndexOfWasmCompilationUnit(WasmCompilationUnit* unit) {
+ return unit->index_;
+}
+
+Handle<Code> FinishCompilation(WasmCompilationUnit* unit) {
+ Handle<Code> result = unit->FinishCompilation();
+ delete unit;
+ return result;
+}
+
+// Helper function to compile a single function.
+Handle<Code> CompileWasmFunction(wasm::ErrorThrower* thrower, Isolate* isolate,
+ wasm::ModuleEnv* module_env,
+ const wasm::WasmFunction* function) {
+ WasmCompilationUnit* unit =
+ CreateWasmCompilationUnit(thrower, isolate, module_env, function, 0);
+ ExecuteCompilation(unit);
+ return FinishCompilation(unit);
+}
} // namespace compiler
} // namespace internal