Index: src/wasm/asm-wasm-builder.cc |
diff --git a/src/wasm/asm-wasm-builder.cc b/src/wasm/asm-wasm-builder.cc |
index ee5427b174d11e8736ca08af45e605e55f3ca8ab..abb69d5678565b5ebe91efa18f98c1dc1365e672 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,58 @@ class AsmWasmBuilderImpl : public AstVisitor { |
RECURSE(Visit(expr->else_expression())); |
} |
+ bool VisitStdlibConstant(Variable* var) { |
+ AsmTyper::StandardMember standard_object = |
+ typer_->VariableAsStandardMember(var); |
+ double value; |
+ switch (standard_object) { |
+ case AsmTyper::kInfinity: { |
+ value = std::numeric_limits<double>::infinity(); |
+ break; |
+ } |
+ case AsmTyper::kNaN: { |
+ value = std::numeric_limits<double>::quiet_NaN(); |
+ break; |
+ } |
+ case AsmTyper::kMathE: { |
+ value = M_E; |
+ break; |
+ } |
+ case AsmTyper::kMathLN10: { |
+ value = M_LN10; |
+ break; |
+ } |
+ case AsmTyper::kMathLN2: { |
+ value = M_LN2; |
+ break; |
+ } |
+ case AsmTyper::kMathLOG10E: { |
+ value = M_LOG10E; |
+ break; |
+ } |
+ case AsmTyper::kMathLOG2E: { |
+ value = M_LOG2E; |
+ break; |
+ } |
+ case AsmTyper::kMathPI: { |
+ value = M_PI; |
+ break; |
+ } |
+ case AsmTyper::kMathSQRT1_2: { |
+ value = M_SQRT1_2; |
+ break; |
+ } |
+ case AsmTyper::kMathSQRT2: { |
+ value = M_SQRT2; |
+ break; |
+ } |
+ default: { return false; } |
+ } |
+ byte code[] = {WASM_F64(value)}; |
+ current_function_builder_->EmitCode(code, sizeof(code)); |
+ return true; |
+ } |
+ |
void VisitVariableProxy(VariableProxy* expr) { |
if (in_function_) { |
Variable* var = expr->var(); |
@@ -382,6 +441,9 @@ class AsmWasmBuilderImpl : public AstVisitor { |
} |
is_set_op_ = false; |
} else { |
+ if (VisitStdlibConstant(var)) { |
+ return; |
+ } |
if (var->IsContextSlot()) { |
current_function_builder_->Emit(kExprLoadGlobal); |
} else { |
@@ -589,29 +651,33 @@ class AsmWasmBuilderImpl : public AstVisitor { |
UnLoadInitFunction(); |
return; |
} |
- // TODO(bradnelson): Get rid of this. |
- if (TypeOf(expr->value()) == kAstStmt) { |
- Property* prop = expr->value()->AsProperty(); |
- if (prop != nullptr) { |
- VariableProxy* vp = prop->obj()->AsVariableProxy(); |
- if (vp != nullptr && vp->var()->IsParameter() && |
- vp->var()->index() == 1) { |
- VariableProxy* target = expr->target()->AsVariableProxy(); |
- if (target->bounds().lower->Is(Type::Function())) { |
- const AstRawString* name = |
- prop->key()->AsLiteral()->AsRawPropertyName(); |
- imported_function_table_.AddImport( |
- target->var(), name->raw_data(), name->length()); |
- } |
- } |
- } |
- ArrayLiteral* funcs = expr->value()->AsArrayLiteral(); |
- if (funcs != nullptr && |
- funcs->bounds().lower->AsArray()->Element()->IsFunction()) { |
+ Property* prop = expr->value()->AsProperty(); |
+ if (prop != nullptr) { |
+ VariableProxy* vp = prop->obj()->AsVariableProxy(); |
+ if (vp != nullptr && vp->var()->IsParameter() && |
+ vp->var()->index() == 1) { |
VariableProxy* target = expr->target()->AsVariableProxy(); |
- DCHECK_NOT_NULL(target); |
- AddFunctionTable(target, funcs); |
+ if (target->bounds().lower->Is(Type::Function())) { |
+ const AstRawString* name = |
+ prop->key()->AsLiteral()->AsRawPropertyName(); |
+ imported_function_table_.AddImport(target->var(), name->raw_data(), |
+ name->length()); |
+ } |
} |
+ // Property values in module scope don't emit code, so return. |
+ return; |
+ } |
+ ArrayLiteral* funcs = expr->value()->AsArrayLiteral(); |
+ if (funcs != nullptr && |
+ funcs->bounds().lower->AsArray()->Element()->IsFunction()) { |
+ VariableProxy* target = expr->target()->AsVariableProxy(); |
+ DCHECK_NOT_NULL(target); |
+ AddFunctionTable(target, funcs); |
+ // Only add to the function table. No init needed. |
+ return; |
+ } |
+ if (expr->value()->IsCallNew()) { |
+ // No init code to emit for CallNew nodes. |
return; |
} |
in_init = true; |
@@ -765,11 +831,166 @@ 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. |
titzer
2016/02/23 15:57:58
Are we collecting tests for these somewhere?
bradn
2016/02/23 16:17:09
Will do.
|
+ 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 != nullptr) { |
+ 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: { |
+ UNREACHABLE(); |
+ break; |
+ } |
+ } |
+ VisitCallArgs(call); |
+ return true; |
+ } |
+ |
+ void VisitCallArgs(Call* expr) { |
+ ZoneList<Expression*>* args = expr->arguments(); |
+ for (int i = 0; i < args->length(); ++i) { |
+ Expression* arg = args->at(i); |
+ RECURSE(Visit(arg)); |
+ } |
+ } |
+ |
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 != nullptr) { |
+ if (VisitStdlibFunction(expr, proxy)) { |
+ return; |
+ } |
+ } |
uint16_t index; |
VariableProxy* vp = expr->expression()->AsVariableProxy(); |
if (vp != nullptr && |
@@ -813,11 +1034,7 @@ class AsmWasmBuilderImpl : public AstVisitor { |
default: |
UNREACHABLE(); |
} |
- ZoneList<Expression*>* args = expr->arguments(); |
- for (int i = 0; i < args->length(); ++i) { |
- Expression* arg = args->at(i); |
- RECURSE(Visit(arg)); |
- } |
+ VisitCallArgs(expr); |
} |
void VisitCallNew(CallNew* expr) { UNREACHABLE(); } |
@@ -1262,6 +1479,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_; |
@@ -1277,13 +1495,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_); |