Index: src/wasm/asm-wasm-builder.cc |
diff --git a/src/wasm/asm-wasm-builder.cc b/src/wasm/asm-wasm-builder.cc |
index 00f459316f6a4d69581f1ca6039ccb9b3222b386..b70aa34999136ef1bf61718349446e0dbdc6b02b 100644 |
--- a/src/wasm/asm-wasm-builder.cc |
+++ b/src/wasm/asm-wasm-builder.cc |
@@ -4,6 +4,12 @@ |
#include "src/v8.h" |
+// Required to get M_E etc. in MSVC. |
+#if defined(_WIN32) |
+#define _USE_MATH_DEFINES |
+#endif |
+#include <math.h> |
+ |
#include "src/wasm/asm-wasm-builder.h" |
#include "src/wasm/wasm-macro-gen.h" |
#include "src/wasm/wasm-opcodes.h" |
@@ -28,7 +34,7 @@ namespace wasm { |
class AsmWasmBuilderImpl : public AstVisitor { |
public: |
AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal, |
- Handle<Object> foreign) |
+ Handle<Object> foreign, AsmTyper* typer) |
: local_variables_(HashMap::PointersMatch, |
ZoneHashMap::kDefaultHashMapCapacity, |
ZoneAllocationPolicy(zone)), |
@@ -46,6 +52,7 @@ class AsmWasmBuilderImpl : public AstVisitor { |
isolate_(isolate), |
zone_(zone), |
foreign_(foreign), |
+ typer_(typer), |
cache_(TypeCache::Get()), |
breakable_blocks_(zone), |
block_size_(0), |
@@ -371,6 +378,67 @@ class AsmWasmBuilderImpl : public AstVisitor { |
RECURSE(Visit(expr->else_expression())); |
} |
+ bool VisitStdlibConstant(Variable* var) { |
+ AsmTyper::StandardMember standard_object = |
+ typer_->VariableAsStandardMember(var); |
+ switch (standard_object) { |
+ case AsmTyper::kInfinity: { |
+ double infinity = std::numeric_limits<double>::infinity(); |
+ byte code[] = {WASM_F64(infinity)}; |
+ current_function_builder_->EmitCode(code, sizeof(code)); |
aseemgarg
2016/02/22 22:15:53
move the EmitCode and return to outside of cases a
bradnelson
2016/02/23 09:48:54
Done.
|
+ return true; |
+ } |
+ case AsmTyper::kNaN: { |
+ double nan = std::numeric_limits<double>::signaling_NaN(); |
+ byte code[] = {WASM_F64(nan)}; |
+ current_function_builder_->EmitCode(code, sizeof(code)); |
+ return true; |
+ } |
+ case AsmTyper::kMathE: { |
+ byte code[] = {WASM_F64(M_E)}; |
+ current_function_builder_->EmitCode(code, sizeof(code)); |
+ return true; |
+ } |
+ case AsmTyper::kMathLN10: { |
+ byte code[] = {WASM_F64(M_LN10)}; |
+ current_function_builder_->EmitCode(code, sizeof(code)); |
+ return true; |
+ } |
+ case AsmTyper::kMathLN2: { |
+ byte code[] = {WASM_F64(M_LN2)}; |
+ current_function_builder_->EmitCode(code, sizeof(code)); |
+ return true; |
+ } |
+ case AsmTyper::kMathLOG10E: { |
+ byte code[] = {WASM_F64(M_LOG10E)}; |
+ current_function_builder_->EmitCode(code, sizeof(code)); |
+ return true; |
+ } |
+ case AsmTyper::kMathLOG2E: { |
+ byte code[] = {WASM_F64(M_LOG2E)}; |
+ current_function_builder_->EmitCode(code, sizeof(code)); |
+ return true; |
+ } |
+ case AsmTyper::kMathPI: { |
+ byte code[] = {WASM_F64(M_PI)}; |
+ current_function_builder_->EmitCode(code, sizeof(code)); |
+ return true; |
+ } |
+ case AsmTyper::kMathSQRT1_2: { |
+ byte code[] = {WASM_F64(M_SQRT1_2)}; |
+ current_function_builder_->EmitCode(code, sizeof(code)); |
+ return true; |
+ } |
+ case AsmTyper::kMathSQRT2: { |
+ byte code[] = {WASM_F64(M_SQRT2)}; |
+ current_function_builder_->EmitCode(code, sizeof(code)); |
+ return true; |
+ } |
+ default: { break; } |
+ } |
+ return false; |
+ } |
+ |
void VisitVariableProxy(VariableProxy* expr) { |
if (in_function_) { |
Variable* var = expr->var(); |
@@ -382,6 +450,9 @@ class AsmWasmBuilderImpl : public AstVisitor { |
} |
is_set_op_ = false; |
} else { |
+ if (VisitStdlibConstant(var)) { |
+ return; |
+ } |
if (var->IsContextSlot()) { |
current_function_builder_->Emit(kExprLoadGlobal); |
} else { |
@@ -589,6 +660,13 @@ class AsmWasmBuilderImpl : public AstVisitor { |
UnLoadInitFunction(); |
return; |
} |
+ Property* prop = expr->value()->AsProperty(); |
aseemgarg
2016/02/22 22:15:53
This doesn't seem quite right. Stdlib constants wo
bradnelson
2016/02/23 09:48:54
So unlike foreign globals, stdlib functions come i
|
+ if (prop != nullptr) { |
+ if (TypeOf(expr->value()) != kAstStmt) { |
+ // Assume it's part of stdlib. |
+ return; |
+ } |
+ } |
// TODO(bradnelson): Get rid of this. |
if (TypeOf(expr->value()) == kAstStmt) { |
Property* prop = expr->value()->AsProperty(); |
@@ -765,11 +843,159 @@ class AsmWasmBuilderImpl : public AstVisitor { |
UNREACHABLE(); |
} |
+ bool VisitStdlibFunction(Call* call, VariableProxy* expr) { |
+ Variable* var = expr->var(); |
+ AsmTyper::StandardMember standard_object = |
+ typer_->VariableAsStandardMember(var); |
+ ZoneList<Expression*>* args = call->arguments(); |
+ LocalType call_type = TypeOf(call); |
+ switch (standard_object) { |
+ case AsmTyper::kNone: { |
+ return false; |
+ } |
+ case AsmTyper::kMathAcos: { |
+ UNREACHABLE(); |
+ break; // TODO(bradnelson): Implement as external. |
+ } |
+ case AsmTyper::kMathAsin: { |
+ UNREACHABLE(); |
+ break; // TODO(bradnelson): Implement as external. |
+ } |
+ case AsmTyper::kMathAtan: { |
+ UNREACHABLE(); |
+ break; // TODO(bradnelson): Implement as external. |
+ } |
+ case AsmTyper::kMathCos: { |
+ UNREACHABLE(); |
+ break; // TODO(bradnelson): Implement as external. |
+ } |
+ case AsmTyper::kMathSin: { |
+ UNREACHABLE(); |
+ break; // TODO(bradnelson): Implement as external. |
+ } |
+ case AsmTyper::kMathTan: { |
+ UNREACHABLE(); |
+ break; // TODO(bradnelson): Implement as external. |
+ } |
+ case AsmTyper::kMathExp: { |
+ UNREACHABLE(); |
+ break; // TODO(bradnelson): Implement as external. |
+ } |
+ case AsmTyper::kMathLog: { |
+ UNREACHABLE(); |
+ break; // TODO(bradnelson): Implement as external. |
+ } |
+ case AsmTyper::kMathCeil: { |
+ if (call_type == kAstF32) { |
+ current_function_builder_->Emit(kExprF32Ceil); |
+ } else if (call_type == kAstF64) { |
+ current_function_builder_->Emit(kExprF64Ceil); |
+ } else { |
+ UNREACHABLE(); |
+ } |
+ break; |
+ } |
+ case AsmTyper::kMathFloor: { |
+ if (call_type == kAstF32) { |
+ current_function_builder_->Emit(kExprF32Floor); |
+ } else if (call_type == kAstF64) { |
+ current_function_builder_->Emit(kExprF64Floor); |
+ } else { |
+ UNREACHABLE(); |
+ } |
+ break; |
+ } |
+ case AsmTyper::kMathSqrt: { |
+ if (call_type == kAstF32) { |
+ current_function_builder_->Emit(kExprF32Sqrt); |
+ } else if (call_type == kAstF64) { |
+ current_function_builder_->Emit(kExprF64Sqrt); |
+ } else { |
+ UNREACHABLE(); |
+ } |
+ break; |
+ } |
+ case AsmTyper::kMathAbs: { |
+ // TODO(bradnelson): Handle signed. |
+ if (call_type == kAstF32) { |
+ current_function_builder_->Emit(kExprF32Abs); |
+ } else if (call_type == kAstF64) { |
+ current_function_builder_->Emit(kExprF64Abs); |
+ } else { |
+ UNREACHABLE(); |
+ } |
+ break; |
+ } |
+ case AsmTyper::kMathMin: { |
+ // TODO(bradnelson): Handle signed. |
+ // TODO(bradnelson): Change wasm to match Math.min in asm.js mode. |
+ if (call_type == kAstF32) { |
+ current_function_builder_->Emit(kExprF32Min); |
+ } else if (call_type == kAstF64) { |
+ current_function_builder_->Emit(kExprF64Min); |
+ } else { |
+ UNREACHABLE(); |
+ } |
+ break; |
+ } |
+ case AsmTyper::kMathMax: { |
+ // TODO(bradnelson): Handle signed. |
+ // TODO(bradnelson): Change wasm to match Math.max in asm.js mode. |
+ if (call_type == kAstF32) { |
+ current_function_builder_->Emit(kExprF32Max); |
+ } else if (call_type == kAstF64) { |
+ current_function_builder_->Emit(kExprF64Max); |
+ } else { |
+ UNREACHABLE(); |
+ } |
+ break; |
+ } |
+ case AsmTyper::kMathAtan2: { |
+ UNREACHABLE(); |
+ break; // TODO(bradnelson): Implement as external. |
+ } |
+ case AsmTyper::kMathPow: { |
+ UNREACHABLE(); |
+ break; // TODO(bradnelson): Implement as external. |
+ } |
+ case AsmTyper::kMathImul: { |
+ current_function_builder_->Emit(kExprI32Mul); |
+ break; |
+ } |
+ case AsmTyper::kMathFround: { |
+ DCHECK(args->length() == 1); |
+ Literal* literal = args->at(0)->AsLiteral(); |
+ if (literal != NULL) { |
+ if (literal->raw_value()->IsNumber()) { |
+ float val = static_cast<float>(literal->raw_value()->AsNumber()); |
+ byte code[] = {WASM_F32(val)}; |
+ current_function_builder_->EmitCode(code, sizeof(code)); |
+ return true; |
+ } |
+ } |
+ break; |
+ } |
+ default: { break; } |
+ } |
+ // Visit arguments. |
aseemgarg
2016/02/22 22:15:53
The visiting of args should be done in the visit c
bradnelson
2016/02/23 09:48:55
So sharing the later call is tricky, as Fround wan
|
+ for (int i = 0; i < args->length(); ++i) { |
+ Expression* arg = args->at(i); |
+ Visit(arg); |
+ } |
+ return true; |
+ } |
+ |
void VisitCall(Call* expr) { |
Call::CallType call_type = expr->GetCallType(isolate_); |
switch (call_type) { |
case Call::OTHER_CALL: { |
DCHECK(in_function_); |
+ VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
+ if (proxy != NULL) { |
+ if (VisitStdlibFunction(expr, proxy)) { |
+ return; |
+ } |
+ } |
uint16_t index; |
VariableProxy* vp = expr->expression()->AsVariableProxy(); |
if (vp != nullptr && |
@@ -1266,6 +1492,7 @@ class AsmWasmBuilderImpl : public AstVisitor { |
Isolate* isolate_; |
Zone* zone_; |
Handle<Object> foreign_; |
+ AsmTyper* typer_; |
TypeCache const& cache_; |
ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_; |
int block_size_; |
@@ -1281,13 +1508,18 @@ class AsmWasmBuilderImpl : public AstVisitor { |
}; |
AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone, |
- FunctionLiteral* literal, Handle<Object> foreign) |
- : isolate_(isolate), zone_(zone), literal_(literal), foreign_(foreign) {} |
+ FunctionLiteral* literal, Handle<Object> foreign, |
+ AsmTyper* typer) |
+ : isolate_(isolate), |
+ zone_(zone), |
+ literal_(literal), |
+ foreign_(foreign), |
+ typer_(typer) {} |
// TODO(aseemgarg): probably should take zone (to write wasm to) as input so |
// that zone in constructor may be thrown away once wasm module is written. |
WasmModuleIndex* AsmWasmBuilder::Run() { |
- AsmWasmBuilderImpl impl(isolate_, zone_, literal_, foreign_); |
+ AsmWasmBuilderImpl impl(isolate_, zone_, literal_, foreign_, typer_); |
impl.Compile(); |
WasmModuleWriter* writer = impl.builder_->Build(zone_); |
return writer->WriteTo(zone_); |