Commit aa912252 authored by jpp's avatar jpp Committed by Commit bot

V8. ASM-2-WASM. Migrates asm-wasm-builder to the new asm-typer.

BUG= https://bugs.chromium.org/p/v8/issues/detail?id=4203
TEST=mjsunit/wasm/*
LOG=N

Review-Url: https://codereview.chromium.org/2134333003
Cr-Commit-Position: refs/heads/master@{#37729}
parent 819fe046
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
#include "src/api-natives.h" #include "src/api-natives.h"
#include "src/api.h" #include "src/api.h"
#include "src/asmjs/asm-typer.h"
#include "src/asmjs/asm-wasm-builder.h" #include "src/asmjs/asm-wasm-builder.h"
#include "src/asmjs/typing-asm.h"
#include "src/assert-scope.h" #include "src/assert-scope.h"
#include "src/ast/ast.h" #include "src/ast/ast.h"
#include "src/ast/scopes.h" #include "src/ast/scopes.h"
...@@ -59,12 +59,8 @@ i::MaybeHandle<i::FixedArray> CompileModule( ...@@ -59,12 +59,8 @@ i::MaybeHandle<i::FixedArray> CompileModule(
MaybeHandle<FixedArray> AsmJs::ConvertAsmToWasm(ParseInfo* info) { MaybeHandle<FixedArray> AsmJs::ConvertAsmToWasm(ParseInfo* info) {
ErrorThrower thrower(info->isolate(), "Asm.js -> WebAssembly conversion"); ErrorThrower thrower(info->isolate(), "Asm.js -> WebAssembly conversion");
AsmTyper typer(info->isolate(), info->zone(), *(info->script()), wasm::AsmTyper typer(info->isolate(), info->zone(), *(info->script()),
info->literal()); info->literal());
typer.set_fixed_signature(true);
if (i::FLAG_enable_simd_asmjs) {
typer.set_allow_simd(true);
}
if (!typer.Validate()) { if (!typer.Validate()) {
DCHECK(!info->isolate()->has_pending_exception()); DCHECK(!info->isolate()->has_pending_exception());
PrintF("Validation of asm.js module failed: %s", typer.error_message()); PrintF("Validation of asm.js module failed: %s", typer.error_message());
......
...@@ -48,6 +48,9 @@ ...@@ -48,6 +48,9 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
namespace wasm { namespace wasm {
namespace {
static const uint32_t LargestFixNum = std::numeric_limits<int32_t>::max();
} // namespace
using v8::internal::AstNode; using v8::internal::AstNode;
using v8::internal::GetCurrentStackPosition; using v8::internal::GetCurrentStackPosition;
...@@ -122,7 +125,8 @@ AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script, ...@@ -122,7 +125,8 @@ AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script,
ZoneHashMap::kDefaultHashMapCapacity, ZoneHashMap::kDefaultHashMapCapacity,
ZoneAllocationPolicy(zone)), ZoneAllocationPolicy(zone)),
stack_limit_(isolate->stack_guard()->real_climit()), stack_limit_(isolate->stack_guard()->real_climit()),
node_types_(zone_) { node_types_(zone_),
fround_type_(AsmType::FroundType(zone_)) {
InitializeStdlib(); InitializeStdlib();
module_info_.set_standard_member(kModule); module_info_.set_standard_member(kModule);
} }
...@@ -165,12 +169,16 @@ void AsmTyper::InitializeStdlib() { ...@@ -165,12 +169,16 @@ void AsmTyper::InitializeStdlib() {
ii2s->AsFunctionType()->AddArgument(i); ii2s->AsFunctionType()->AddArgument(i);
auto* minmax_d = AsmType::MinMaxType(zone_, d, d); auto* minmax_d = AsmType::MinMaxType(zone_, d, d);
// *VIOLATION* The float variant is not part of the spec, but firefox accepts
// it.
auto* minmax_f = AsmType::MinMaxType(zone_, f, f);
auto* minmax_i = AsmType::MinMaxType(zone_, s, i); auto* minmax_i = AsmType::MinMaxType(zone_, s, i);
auto* minmax = AsmType::OverloadedFunction(zone_); auto* minmax = AsmType::OverloadedFunction(zone_);
minmax->AsOverloadedFunctionType()->AddOverload(minmax_i); minmax->AsOverloadedFunctionType()->AddOverload(minmax_i);
minmax->AsOverloadedFunctionType()->AddOverload(minmax_f);
minmax->AsOverloadedFunctionType()->AddOverload(minmax_d); minmax->AsOverloadedFunctionType()->AddOverload(minmax_d);
auto* fround = AsmType::FroundType(zone_); auto* fround = fround_type_;
auto* abs = AsmType::OverloadedFunction(zone_); auto* abs = AsmType::OverloadedFunction(zone_);
abs->AsOverloadedFunctionType()->AddOverload(s2s); abs->AsOverloadedFunctionType()->AddOverload(s2s);
...@@ -362,17 +370,36 @@ bool AsmTyper::AddLocal(Variable* variable, VariableInfo* info) { ...@@ -362,17 +370,36 @@ bool AsmTyper::AddLocal(Variable* variable, VariableInfo* info) {
void AsmTyper::SetTypeOf(AstNode* node, AsmType* type) { void AsmTyper::SetTypeOf(AstNode* node, AsmType* type) {
DCHECK_NE(type, AsmType::None()); DCHECK_NE(type, AsmType::None());
auto** node_type = &node_types_[node]; DCHECK(node_types_.find(node) == node_types_.end());
DCHECK(*node_type == nullptr); node_types_.insert(std::make_pair(node, type));
*node_type = type;
} }
AsmType* AsmTyper::TypeOf(AstNode* node) const { AsmType* AsmTyper::TypeOf(AstNode* node) const {
auto node_type_iter = node_types_.find(node); auto node_type_iter = node_types_.find(node);
if (node_type_iter == node_types_.end()) { if (node_type_iter != node_types_.end()) {
return AsmType::None(); return node_type_iter->second;
}
// Sometimes literal nodes are not added to the node_type_ map simply because
// their are not visited with ValidateExpression().
if (auto* literal = node->AsLiteral()) {
if (literal->raw_value()->ContainsDot()) {
return AsmType::Double();
}
uint32_t u;
if (literal->value()->ToUint32(&u)) {
if (u > LargestFixNum) {
return AsmType::Unsigned();
}
return AsmType::FixNum();
}
int32_t i;
if (literal->value()->ToInt32(&i)) {
return AsmType::Signed();
}
} }
return node_type_iter->second;
return AsmType::None();
} }
AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) { AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) {
...@@ -607,11 +634,13 @@ AsmType* AsmTyper::ValidateGlobalDeclaration(Assignment* assign) { ...@@ -607,11 +634,13 @@ AsmType* AsmTyper::ValidateGlobalDeclaration(Assignment* assign) {
auto* value = assign->value(); auto* value = assign->value();
// Not all types of assignment are allowed by asm.js. See // Not all types of assignment are allowed by asm.js. See
// 5.5 Global Variable Type Annotations. // 5.5 Global Variable Type Annotations.
bool global_variable = false;
if (value->IsLiteral() || value->IsCall()) { if (value->IsLiteral() || value->IsCall()) {
AsmType* type = nullptr; AsmType* type = nullptr;
RECURSE(type = VariableTypeAnnotations(value)); RECURSE(type = VariableTypeAnnotations(value));
target_info = new (zone_) VariableInfo(type); target_info = new (zone_) VariableInfo(type);
target_info->set_mutability(VariableInfo::kMutableGlobal); target_info->set_mutability(VariableInfo::kMutableGlobal);
global_variable = true;
} else if (value->IsProperty()) { } else if (value->IsProperty()) {
target_info = ImportLookup(value->AsProperty()); target_info = ImportLookup(value->AsProperty());
if (target_info == nullptr) { if (target_info == nullptr) {
...@@ -689,6 +718,12 @@ AsmType* AsmTyper::ValidateGlobalDeclaration(Assignment* assign) { ...@@ -689,6 +718,12 @@ AsmType* AsmTyper::ValidateGlobalDeclaration(Assignment* assign) {
} }
DCHECK(target_info->type() != AsmType::None()); DCHECK(target_info->type() != AsmType::None());
if (!global_variable) {
// Global variables have their types set in VariableTypeAnnotations.
SetTypeOf(value, target_info->type());
}
SetTypeOf(assign, target_info->type());
SetTypeOf(target, target_info->type());
return target_info->type(); return target_info->type();
} }
...@@ -830,6 +865,7 @@ AsmType* AsmTyper::ValidateFunctionTable(Assignment* assign) { ...@@ -830,6 +865,7 @@ AsmType* AsmTyper::ValidateFunctionTable(Assignment* assign) {
DCHECK(false); DCHECK(false);
FAIL(assign, "Redeclared global identifier in function table name."); FAIL(assign, "Redeclared global identifier in function table name.");
} }
SetTypeOf(value, target_info->type());
return target_info->type(); return target_info->type();
} }
...@@ -854,7 +890,7 @@ AsmType* AsmTyper::ValidateFunctionTable(Assignment* assign) { ...@@ -854,7 +890,7 @@ AsmType* AsmTyper::ValidateFunctionTable(Assignment* assign) {
} }
target_info->MarkDefined(); target_info->MarkDefined();
DCHECK(target_info->type() == AsmType::None()); DCHECK(target_info->type() != AsmType::None());
SetTypeOf(value, target_info->type()); SetTypeOf(value, target_info->type());
return target_info->type(); return target_info->type();
...@@ -916,6 +952,8 @@ AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) { ...@@ -916,6 +952,8 @@ AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) {
FAIL(proxy, "Redeclared parameter."); FAIL(proxy, "Redeclared parameter.");
} }
parameter_types.push_back(type); parameter_types.push_back(type);
SetTypeOf(proxy, type);
SetTypeOf(expr, type);
} }
if (annotated_parameters != fun->parameter_count()) { if (annotated_parameters != fun->parameter_count()) {
...@@ -952,6 +990,9 @@ AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) { ...@@ -952,6 +990,9 @@ AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) {
if (!AddLocal(local->var(), local_info)) { if (!AddLocal(local->var(), local_info)) {
FAIL(initializer, "Redeclared local."); FAIL(initializer, "Redeclared local.");
} }
SetTypeOf(local, type);
SetTypeOf(initializer, type);
} }
// 5.2 Return Type Annotations // 5.2 Return Type Annotations
...@@ -1018,6 +1059,8 @@ AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) { ...@@ -1018,6 +1059,8 @@ AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) {
DCHECK(false); DCHECK(false);
FAIL(fun_decl, "Redeclared global identifier."); FAIL(fun_decl, "Redeclared global identifier.");
} }
SetTypeOf(fun, fun_type);
return fun_type; return fun_type;
} }
...@@ -1221,6 +1264,7 @@ AsmType* AsmTyper::ValidateSwitchStatement(SwitchStatement* stmt) { ...@@ -1221,6 +1264,7 @@ AsmType* AsmTyper::ValidateSwitchStatement(SwitchStatement* stmt) {
CHECK(!has_default); CHECK(!has_default);
RECURSE(ValidateDefault(a_case)); RECURSE(ValidateDefault(a_case));
has_default = true; has_default = true;
continue;
} }
int32_t case_lbl; int32_t case_lbl;
...@@ -1364,7 +1408,7 @@ bool IsUnaryMinus(BinaryOperation* binop) { ...@@ -1364,7 +1408,7 @@ bool IsUnaryMinus(BinaryOperation* binop) {
return false; return false;
} }
return right_as_literal->raw_value()->ContainsDot() && return !right_as_literal->raw_value()->ContainsDot() &&
right_as_literal->raw_value()->AsNumber() == -1.0; right_as_literal->raw_value()->AsNumber() == -1.0;
} }
} // namespace } // namespace
...@@ -1391,6 +1435,7 @@ AsmType* AsmTyper::ValidateBinaryOperation(BinaryOperation* expr) { ...@@ -1391,6 +1435,7 @@ AsmType* AsmTyper::ValidateBinaryOperation(BinaryOperation* expr) {
} }
AsmType* left_type; AsmType* left_type;
RECURSE(left_type = ValidateExpression(expr->left())); RECURSE(left_type = ValidateExpression(expr->left()));
SetTypeOf(expr->right(), AsmType::Double());
UNOP_OVERLOAD(Signed, Double); UNOP_OVERLOAD(Signed, Double);
UNOP_OVERLOAD(Unsigned, Double); UNOP_OVERLOAD(Unsigned, Double);
UNOP_OVERLOAD(DoubleQ, Double); UNOP_OVERLOAD(DoubleQ, Double);
...@@ -1402,6 +1447,7 @@ AsmType* AsmTyper::ValidateBinaryOperation(BinaryOperation* expr) { ...@@ -1402,6 +1447,7 @@ AsmType* AsmTyper::ValidateBinaryOperation(BinaryOperation* expr) {
// *VIOLATION* the parser converts -x to x * -1.0. // *VIOLATION* the parser converts -x to x * -1.0.
AsmType* left_type; AsmType* left_type;
RECURSE(left_type = ValidateExpression(expr->left())); RECURSE(left_type = ValidateExpression(expr->left()));
SetTypeOf(expr->right(), left_type);
UNOP_OVERLOAD(Int, Intish); UNOP_OVERLOAD(Int, Intish);
UNOP_OVERLOAD(DoubleQ, Double); UNOP_OVERLOAD(DoubleQ, Double);
UNOP_OVERLOAD(FloatQ, Floatish); UNOP_OVERLOAD(FloatQ, Floatish);
...@@ -1431,6 +1477,9 @@ AsmType* AsmTyper::ValidateBinaryOperation(BinaryOperation* expr) { ...@@ -1431,6 +1477,9 @@ AsmType* AsmTyper::ValidateBinaryOperation(BinaryOperation* expr) {
// This is the special ~~ operator. // This is the special ~~ operator.
AsmType* left_type; AsmType* left_type;
RECURSE(left_type = ValidateExpression(left_as_binop->left())); RECURSE(left_type = ValidateExpression(left_as_binop->left()));
SetTypeOf(left_as_binop->right(), AsmType::FixNum());
SetTypeOf(left_as_binop, AsmType::Signed());
SetTypeOf(expr->right(), AsmType::FixNum());
UNOP_OVERLOAD(Double, Signed); UNOP_OVERLOAD(Double, Signed);
UNOP_OVERLOAD(FloatQ, Signed); UNOP_OVERLOAD(FloatQ, Signed);
FAIL(left_as_binop, "Invalid type for conversion to signed."); FAIL(left_as_binop, "Invalid type for conversion to signed.");
...@@ -1456,24 +1505,21 @@ AsmType* AsmTyper::ValidateCommaExpression(BinaryOperation* comma) { ...@@ -1456,24 +1505,21 @@ AsmType* AsmTyper::ValidateCommaExpression(BinaryOperation* comma) {
// (expr COMMA (expr COMMA (expr COMMA (... )))) // (expr COMMA (expr COMMA (expr COMMA (... ))))
auto* left = comma->left(); auto* left = comma->left();
auto* left_as_binop = left->AsBinaryOperation(); if (auto* left_as_call = left->AsCall()) {
if (left_as_binop && left_as_binop->op() == Token::COMMA) { RECURSE(ValidateCall(AsmType::Void(), left_as_call));
ValidateCommaExpression(left_as_binop);
} else if (auto* left_as_call = left->AsCall()) {
ValidateCall(AsmType::Void(), left_as_call);
} else { } else {
ValidateExpression(left); RECURSE(ValidateExpression(left));
} }
auto* right = comma->right(); auto* right = comma->right();
auto* right_as_binop = right->AsBinaryOperation(); AsmType* right_type = nullptr;
if (right_as_binop && right_as_binop->op() == Token::COMMA) { if (auto* right_as_call = right->AsCall()) {
return ValidateCommaExpression(right_as_binop); RECURSE(right_type = ValidateCall(AsmType::Void(), right_as_call));
} else { } else {
return ValidateExpression(right); RECURSE(right_type = ValidateExpression(right));
} }
UNREACHABLE(); return right_type;
} }
// 6.8.2 NumericLiteral // 6.8.2 NumericLiteral
...@@ -1500,7 +1546,6 @@ AsmType* AsmTyper::ValidateNumericLiteral(Literal* literal) { ...@@ -1500,7 +1546,6 @@ AsmType* AsmTyper::ValidateNumericLiteral(Literal* literal) {
return AsmType::Signed(); return AsmType::Signed();
} }
static const uint32_t LargestFixNum = std::numeric_limits<int32_t>::max();
if (value <= LargestFixNum) { if (value <= LargestFixNum) {
return AsmType::FixNum(); return AsmType::FixNum();
} }
...@@ -1587,13 +1632,15 @@ AsmType* AsmTyper::ValidateAssignmentExpression(Assignment* assignment) { ...@@ -1587,13 +1632,15 @@ AsmType* AsmTyper::ValidateAssignmentExpression(Assignment* assignment) {
ValidateHeapAccess(target_as_property, StoreToHeap)); ValidateHeapAccess(target_as_property, StoreToHeap));
// TODO(jpp): Change FloatishDoubleQ and FloatQDoubleQ so that they are base // TODO(jpp): Change FloatishDoubleQ and FloatQDoubleQ so that they are base
// classes for Floatish, DoubleQ, and FloatQ, and then invert this if so // classes for Floatish, DoubleQ, and FloatQ.
// that it reads more naturally as if (allowed_store_types == AsmType::FloatishDoubleQ()) {
// if (!value_type->IsA(AsmType::Floatish()) &&
// if (!value_type->IsA(allowed_store_types)) !value_type->IsA(AsmType::DoubleQ())) {
if (allowed_store_types == AsmType::FloatishDoubleQ() || FAIL(assignment, "Type mismatch in heap assignment.");
allowed_store_types == AsmType::FloatQDoubleQ()) { }
if (!allowed_store_types->IsA(value_type)) { } else if (allowed_store_types == AsmType::FloatQDoubleQ()) {
if (!value_type->IsA(AsmType::FloatQ()) &&
!value_type->IsA(AsmType::DoubleQ())) {
FAIL(assignment, "Type mismatch in heap assignment."); FAIL(assignment, "Type mismatch in heap assignment.");
} }
} else { } else {
...@@ -1778,6 +1825,7 @@ AsmType* AsmTyper::ValidateAdditiveExpression(BinaryOperation* binop, ...@@ -1778,6 +1825,7 @@ AsmType* AsmTyper::ValidateAdditiveExpression(BinaryOperation* binop,
left_as_binop->op() == Token::SUB)) { left_as_binop->op() == Token::SUB)) {
RECURSE(left_type = RECURSE(left_type =
ValidateAdditiveExpression(left_as_binop, intish_count + 1)); ValidateAdditiveExpression(left_as_binop, intish_count + 1));
SetTypeOf(left_as_binop, left_type);
} else { } else {
RECURSE(left_type = ValidateExpression(left)); RECURSE(left_type = ValidateExpression(left));
} }
...@@ -1790,6 +1838,7 @@ AsmType* AsmTyper::ValidateAdditiveExpression(BinaryOperation* binop, ...@@ -1790,6 +1838,7 @@ AsmType* AsmTyper::ValidateAdditiveExpression(BinaryOperation* binop,
right_as_binop->op() == Token::SUB)) { right_as_binop->op() == Token::SUB)) {
RECURSE(right_type = RECURSE(right_type =
ValidateAdditiveExpression(right_as_binop, intish_count + 1)); ValidateAdditiveExpression(right_as_binop, intish_count + 1));
SetTypeOf(right_as_binop, right_type);
} else { } else {
RECURSE(right_type = ValidateExpression(right)); RECURSE(right_type = ValidateExpression(right));
} }
...@@ -2084,32 +2133,14 @@ bool ExtractIndirectCallMask(Expression* expr, uint32_t* value) { ...@@ -2084,32 +2133,14 @@ bool ExtractIndirectCallMask(Expression* expr, uint32_t* value) {
return base::bits::IsPowerOfTwo32(1 + *value); return base::bits::IsPowerOfTwo32(1 + *value);
} }
// TODO(jpp): Add a AsmType::ValidateCall is poorly designed. It can only handle
// function declarations, not invocations. CheckInvocationOf temporarily works
// around this limitation by converting each actual in actuals to a parameter
// type before invoking prototype->ValidateCall. This is the wrong behavior for
// FFIs (we need to pass Signed integers to FFIs, not Ints), so that case is
// handled separately.
bool CheckInvocationOf(AsmCallableType* prototype, AsmType* return_type,
ZoneVector<AsmType*>* actuals) {
if (auto* ffi = prototype->AsFFIType()) {
return ffi->ValidateCall(return_type, *actuals) != AsmType::None();
}
for (size_t ii = 0; ii < actuals->size(); ++ii) {
(*actuals)[ii] = (*actuals)[ii]->ToParameterType();
}
return prototype->ValidateCall(return_type, *actuals) != AsmType::None();
}
} // namespace } // namespace
AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) { AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) {
AsmType* float_coercion_type; AsmType* float_coercion_type;
RECURSE(float_coercion_type = ValidateFloatCoercion(call)); RECURSE(float_coercion_type = ValidateFloatCoercion(call));
if (float_coercion_type == AsmType::Float()) { if (float_coercion_type == AsmType::Float()) {
return AsmType::Float(); SetTypeOf(call, AsmType::Float());
return return_type;
} }
// TODO(jpp): we should be able to reuse the args vector's storage space. // TODO(jpp): we should be able to reuse the args vector's storage space.
...@@ -2148,6 +2179,8 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) { ...@@ -2148,6 +2179,8 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) {
DCHECK(false); DCHECK(false);
FAIL(call, "Redeclared global identifier."); FAIL(call, "Redeclared global identifier.");
} }
SetTypeOf(call_var_proxy, reinterpret_cast<AsmType*>(call_type));
SetTypeOf(call, return_type);
return return_type; return return_type;
} }
...@@ -2161,10 +2194,12 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) { ...@@ -2161,10 +2194,12 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) {
FAIL(call, "Foreign functions can't return float."); FAIL(call, "Foreign functions can't return float.");
} }
if (!CheckInvocationOf(callee_type, return_type, &args)) { if (!callee_type->CanBeInvokedWith(return_type, args)) {
FAIL(call, "Function invocation does not match function type."); FAIL(call, "Function invocation does not match function type.");
} }
SetTypeOf(call_var_proxy, call_var_info->type());
SetTypeOf(call, return_type);
return return_type; return return_type;
} }
...@@ -2221,6 +2256,8 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) { ...@@ -2221,6 +2256,8 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) {
DCHECK(false); DCHECK(false);
FAIL(call, "Redeclared global identifier."); FAIL(call, "Redeclared global identifier.");
} }
SetTypeOf(call_property, reinterpret_cast<AsmType*>(call_type));
SetTypeOf(call, return_type);
return return_type; return return_type;
} }
...@@ -2236,12 +2273,15 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) { ...@@ -2236,12 +2273,15 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) {
auto* previous_type_signature = auto* previous_type_signature =
previous_type->signature()->AsFunctionType(); previous_type->signature()->AsFunctionType();
DCHECK(previous_type_signature != nullptr); DCHECK(previous_type_signature != nullptr);
if (!CheckInvocationOf(previous_type_signature, return_type, &args)) { if (!previous_type_signature->CanBeInvokedWith(return_type, args)) {
// TODO(jpp): better error messages.
FAIL(call, FAIL(call,
"Function pointer table signature does not match previous " "Function pointer table signature does not match previous "
"signature."); "signature.");
} }
SetTypeOf(call_property, previous_type->signature());
SetTypeOf(call, return_type);
return return_type; return return_type;
} }
...@@ -2280,6 +2320,7 @@ AsmType* AsmTyper::ValidateHeapAccess(Property* heap, ...@@ -2280,6 +2320,7 @@ AsmType* AsmTyper::ValidateHeapAccess(Property* heap,
if (!obj_type->IsA(AsmType::Heap())) { if (!obj_type->IsA(AsmType::Heap())) {
FAIL(heap, "Identifier does not represent a heap view."); FAIL(heap, "Identifier does not represent a heap view.");
} }
SetTypeOf(obj, obj_type);
if (auto* key_as_literal = heap->key()->AsLiteral()) { if (auto* key_as_literal = heap->key()->AsLiteral()) {
if (key_as_literal->raw_value()->ContainsDot()) { if (key_as_literal->raw_value()->ContainsDot()) {
...@@ -2371,6 +2412,7 @@ AsmType* AsmTyper::ValidateFloatCoercion(Call* call) { ...@@ -2371,6 +2412,7 @@ AsmType* AsmTyper::ValidateFloatCoercion(Call* call) {
RECURSE(arg_type = ValidateExpression(arg)); RECURSE(arg_type = ValidateExpression(arg));
if (arg_type->IsA(AsmType::Floatish()) || arg_type->IsA(AsmType::DoubleQ()) || if (arg_type->IsA(AsmType::Floatish()) || arg_type->IsA(AsmType::DoubleQ()) ||
arg_type->IsA(AsmType::Signed()) || arg_type->IsA(AsmType::Unsigned())) { arg_type->IsA(AsmType::Signed()) || arg_type->IsA(AsmType::Unsigned())) {
SetTypeOf(call->expression(), fround_type_);
return AsmType::Float(); return AsmType::Float();
} }
...@@ -2395,9 +2437,11 @@ AsmType* AsmTyper::ParameterTypeAnnotations(Variable* parameter, ...@@ -2395,9 +2437,11 @@ AsmType* AsmTyper::ParameterTypeAnnotations(Variable* parameter,
"Invalid parameter type annotation - should annotate a parameter."); "Invalid parameter type annotation - should annotate a parameter.");
} }
if (IsDoubleAnnotation(binop)) { if (IsDoubleAnnotation(binop)) {
SetTypeOf(left, AsmType::Double());
return AsmType::Double(); return AsmType::Double();
} }
if (IsIntAnnotation(binop)) { if (IsIntAnnotation(binop)) {
SetTypeOf(left, AsmType::Int());
return AsmType::Int(); return AsmType::Int();
} }
FAIL(binop, "Invalid parameter type annotation."); FAIL(binop, "Invalid parameter type annotation.");
...@@ -2428,6 +2472,7 @@ AsmType* AsmTyper::ParameterTypeAnnotations(Variable* parameter, ...@@ -2428,6 +2472,7 @@ AsmType* AsmTyper::ParameterTypeAnnotations(Variable* parameter,
"a parameter."); "a parameter.");
} }
SetTypeOf(src_expr, AsmType::Float());
return AsmType::Float(); return AsmType::Float();
} }
...@@ -2485,18 +2530,26 @@ AsmType* AsmTyper::ReturnTypeAnnotations(ReturnStatement* statement) { ...@@ -2485,18 +2530,26 @@ AsmType* AsmTyper::ReturnTypeAnnotations(ReturnStatement* statement) {
AsmType* AsmTyper::VariableTypeAnnotations(Expression* initializer) { AsmType* AsmTyper::VariableTypeAnnotations(Expression* initializer) {
if (auto* literal = initializer->AsLiteral()) { if (auto* literal = initializer->AsLiteral()) {
if (literal->raw_value()->ContainsDot()) { if (literal->raw_value()->ContainsDot()) {
SetTypeOf(initializer, AsmType::Double());
return AsmType::Double(); return AsmType::Double();
} }
int32_t i32; int32_t i32;
uint32_t u32; uint32_t u32;
if (literal->value()->ToInt32(&i32) || literal->value()->ToUint32(&u32)) { if (literal->value()->ToUint32(&u32)) {
return AsmType::Int(); if (u32 > LargestFixNum) {
SetTypeOf(initializer, AsmType::Unsigned());
} else {
SetTypeOf(initializer, AsmType::FixNum());
}
} else if (literal->value()->ToInt32(&i32)) {
SetTypeOf(initializer, AsmType::Signed());
} else {
FAIL(initializer, "Invalid type annotation - forbidden literal.");
} }
FAIL(initializer, "Invalid type annotation - forbidden literal."); return AsmType::Int();
} }
auto* call = initializer->AsCall(); auto* call = initializer->AsCall();
DCHECK(call != nullptr);
if (call == nullptr) { if (call == nullptr) {
FAIL(initializer, FAIL(initializer,
"Invalid variable initialization - it should be a literal, or " "Invalid variable initialization - it should be a literal, or "
......
...@@ -22,6 +22,7 @@ namespace v8 { ...@@ -22,6 +22,7 @@ namespace v8 {
namespace internal { namespace internal {
namespace wasm { namespace wasm {
class AsmType;
class AsmTyperHarnessBuilder; class AsmTyperHarnessBuilder;
class AsmTyper final { class AsmTyper final {
...@@ -313,6 +314,7 @@ class AsmTyper final { ...@@ -313,6 +314,7 @@ class AsmTyper final {
bool stack_overflow_ = false; bool stack_overflow_ = false;
ZoneMap<AstNode*, AsmType*> node_types_; ZoneMap<AstNode*, AsmType*> node_types_;
static const int kErrorMessageLimit = 100; static const int kErrorMessageLimit = 100;
AsmType* fround_type_;
char error_message_[kErrorMessageLimit]; char error_message_[kErrorMessageLimit];
DISALLOW_IMPLICIT_CONSTRUCTORS(AsmTyper); DISALLOW_IMPLICIT_CONSTRUCTORS(AsmTyper);
......
...@@ -173,6 +173,8 @@ class AsmFroundType final : public AsmFunctionType { ...@@ -173,6 +173,8 @@ class AsmFroundType final : public AsmFunctionType {
AsmType* ValidateCall(AsmType* return_type, AsmType* ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) override; const ZoneVector<AsmType*>& args) override;
bool CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) override;
}; };
} // namespace } // namespace
...@@ -181,6 +183,7 @@ AsmType* AsmType::FroundType(Zone* zone) { ...@@ -181,6 +183,7 @@ AsmType* AsmType::FroundType(Zone* zone) {
return reinterpret_cast<AsmType*>(Fround); return reinterpret_cast<AsmType*>(Fround);
} }
// TODO(jpp): Remove this method.
AsmType* AsmFroundType::ValidateCall(AsmType* return_type, AsmType* AsmFroundType::ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) { const ZoneVector<AsmType*>& args) {
if (args.size() != 1) { if (args.size() != 1) {
...@@ -196,6 +199,21 @@ AsmType* AsmFroundType::ValidateCall(AsmType* return_type, ...@@ -196,6 +199,21 @@ AsmType* AsmFroundType::ValidateCall(AsmType* return_type,
return AsmType::Float(); return AsmType::Float();
} }
bool AsmFroundType::CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) {
if (args.size() != 1) {
return false;
}
auto* arg = args[0];
if (!arg->IsA(AsmType::Floatish()) && !arg->IsA(AsmType::DoubleQ()) &&
!arg->IsA(AsmType::Signed()) && !arg->IsA(AsmType::Unsigned())) {
return false;
}
return true;
}
namespace { namespace {
class AsmMinMaxType final : public AsmFunctionType { class AsmMinMaxType final : public AsmFunctionType {
public: public:
...@@ -228,6 +246,26 @@ class AsmMinMaxType final : public AsmFunctionType { ...@@ -228,6 +246,26 @@ class AsmMinMaxType final : public AsmFunctionType {
return ReturnType(); return ReturnType();
} }
bool CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) override {
if (!ReturnType()->IsExactly(return_type)) {
return false;
}
if (args.size() < 2) {
return false;
}
auto* arg_type = Arguments()[0];
for (size_t ii = 0; ii < Arguments().size(); ++ii) {
if (!args[ii]->IsA(arg_type)) {
return false;
}
}
return true;
}
}; };
} // namespace } // namespace
...@@ -249,6 +287,21 @@ AsmType* AsmFFIType::ValidateCall(AsmType* return_type, ...@@ -249,6 +287,21 @@ AsmType* AsmFFIType::ValidateCall(AsmType* return_type,
return return_type; return return_type;
} }
bool AsmFFIType::CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) {
if (return_type->IsExactly(AsmType::Float())) {
return false;
}
for (size_t ii = 0; ii < args.size(); ++ii) {
if (!args[ii]->IsA(AsmType::Extern())) {
return false;
}
}
return true;
}
AsmType* AsmFunctionType::ValidateCall(AsmType* return_type, AsmType* AsmFunctionType::ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) { const ZoneVector<AsmType*>& args) {
if (!return_type_->IsExactly(return_type)) { if (!return_type_->IsExactly(return_type)) {
...@@ -268,6 +321,25 @@ AsmType* AsmFunctionType::ValidateCall(AsmType* return_type, ...@@ -268,6 +321,25 @@ AsmType* AsmFunctionType::ValidateCall(AsmType* return_type,
return return_type_; return return_type_;
} }
bool AsmFunctionType::CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) {
if (!return_type_->IsExactly(return_type)) {
return false;
}
if (args_.size() != args.size()) {
return false;
}
for (size_t ii = 0; ii < args_.size(); ++ii) {
if (!args[ii]->IsA(args_[ii])) {
return false;
}
}
return true;
}
std::string AsmOverloadedFunctionType::Name() { std::string AsmOverloadedFunctionType::Name() {
std::string ret; std::string ret;
...@@ -294,6 +366,17 @@ AsmType* AsmOverloadedFunctionType::ValidateCall( ...@@ -294,6 +366,17 @@ AsmType* AsmOverloadedFunctionType::ValidateCall(
return AsmType::None(); return AsmType::None();
} }
bool AsmOverloadedFunctionType::CanBeInvokedWith(
AsmType* return_type, const ZoneVector<AsmType*>& args) {
for (size_t ii = 0; ii < overloads_.size(); ++ii) {
if (overloads_[ii]->AsCallableType()->CanBeInvokedWith(return_type, args)) {
return true;
}
}
return false;
}
void AsmOverloadedFunctionType::AddOverload(AsmType* overload) { void AsmOverloadedFunctionType::AddOverload(AsmType* overload) {
DCHECK(overload->AsFunctionType() != nullptr); DCHECK(overload->AsFunctionType() != nullptr);
overloads_.push_back(overload); overloads_.push_back(overload);
...@@ -314,6 +397,11 @@ AsmType* AsmFunctionTableType::ValidateCall(AsmType* return_type, ...@@ -314,6 +397,11 @@ AsmType* AsmFunctionTableType::ValidateCall(AsmType* return_type,
return signature_->AsCallableType()->ValidateCall(return_type, args); return signature_->AsCallableType()->ValidateCall(return_type, args);
} }
bool AsmFunctionTableType::CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) {
return signature_->AsCallableType()->CanBeInvokedWith(return_type, args);
}
} // namespace wasm } // namespace wasm
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -110,6 +110,9 @@ class AsmCallableType : public ZoneObject { ...@@ -110,6 +110,9 @@ class AsmCallableType : public ZoneObject {
virtual AsmType* ValidateCall(AsmType* return_type, virtual AsmType* ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) = 0; const ZoneVector<AsmType*>& args) = 0;
virtual bool CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) = 0;
#define DECLARE_CAST(CamelName) \ #define DECLARE_CAST(CamelName) \
virtual Asm##CamelName* As##CamelName() { return nullptr; } virtual Asm##CamelName* As##CamelName() { return nullptr; }
FOR_EACH_ASM_CALLABLE_TYPE_LIST(DECLARE_CAST) FOR_EACH_ASM_CALLABLE_TYPE_LIST(DECLARE_CAST)
...@@ -136,6 +139,8 @@ class AsmFunctionType : public AsmCallableType { ...@@ -136,6 +139,8 @@ class AsmFunctionType : public AsmCallableType {
AsmType* ValidateCall(AsmType* return_type, AsmType* ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) override; const ZoneVector<AsmType*>& args) override;
bool CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) override;
protected: protected:
AsmFunctionType(Zone* zone, AsmType* return_type) AsmFunctionType(Zone* zone, AsmType* return_type)
...@@ -168,6 +173,8 @@ class AsmOverloadedFunctionType final : public AsmCallableType { ...@@ -168,6 +173,8 @@ class AsmOverloadedFunctionType final : public AsmCallableType {
std::string Name() override; std::string Name() override;
AsmType* ValidateCall(AsmType* return_type, AsmType* ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) override; const ZoneVector<AsmType*>& args) override;
bool CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) override;
ZoneVector<AsmType*> overloads_; ZoneVector<AsmType*> overloads_;
...@@ -181,6 +188,8 @@ class AsmFFIType final : public AsmCallableType { ...@@ -181,6 +188,8 @@ class AsmFFIType final : public AsmCallableType {
std::string Name() override { return "Function"; } std::string Name() override { return "Function"; }
AsmType* ValidateCall(AsmType* return_type, AsmType* ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) override; const ZoneVector<AsmType*>& args) override;
bool CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) override;
private: private:
friend AsmType; friend AsmType;
...@@ -198,6 +207,8 @@ class AsmFunctionTableType : public AsmCallableType { ...@@ -198,6 +207,8 @@ class AsmFunctionTableType : public AsmCallableType {
AsmType* ValidateCall(AsmType* return_type, AsmType* ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) override; const ZoneVector<AsmType*>& args) override;
bool CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) override;
size_t length() const { return length_; } size_t length() const { return length_; }
AsmType* signature() { return signature_; } AsmType* signature() { return signature_; }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#endif #endif
#include <math.h> #include <math.h>
#include "src/asmjs/asm-types.h"
#include "src/asmjs/asm-wasm-builder.h" #include "src/asmjs/asm-wasm-builder.h"
#include "src/wasm/switch-logic.h" #include "src/wasm/switch-logic.h"
#include "src/wasm/wasm-macro-gen.h" #include "src/wasm/wasm-macro-gen.h"
...@@ -18,7 +19,6 @@ ...@@ -18,7 +19,6 @@
#include "src/ast/ast.h" #include "src/ast/ast.h"
#include "src/ast/scopes.h" #include "src/ast/scopes.h"
#include "src/codegen.h" #include "src/codegen.h"
#include "src/type-cache.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -59,7 +59,6 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -59,7 +59,6 @@ class AsmWasmBuilderImpl : public AstVisitor {
isolate_(isolate), isolate_(isolate),
zone_(zone), zone_(zone),
typer_(typer), typer_(typer),
cache_(TypeCache::Get()),
breakable_blocks_(zone), breakable_blocks_(zone),
foreign_variables_(zone), foreign_variables_(zone),
init_function_index_(0), init_function_index_(0),
...@@ -68,8 +67,7 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -68,8 +67,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
function_tables_(base::HashMap::PointersMatch, function_tables_(base::HashMap::PointersMatch,
ZoneHashMap::kDefaultHashMapCapacity, ZoneHashMap::kDefaultHashMapCapacity,
ZoneAllocationPolicy(zone)), ZoneAllocationPolicy(zone)),
imported_function_table_(this), imported_function_table_(this) {
bounds_(typer->bounds()) {
InitializeAstVisitor(isolate); InitializeAstVisitor(isolate);
} }
...@@ -359,12 +357,10 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -359,12 +357,10 @@ class AsmWasmBuilderImpl : public AstVisitor {
if (!clause->is_default()) { if (!clause->is_default()) {
Literal* label = clause->label()->AsLiteral(); Literal* label = clause->label()->AsLiteral();
Handle<Object> value = label->value(); Handle<Object> value = label->value();
DCHECK(value->IsNumber() &&
bounds_->get(label).upper->Is(cache_.kAsmSigned));
int32_t label_value; int32_t label_value;
if (!value->ToInt32(&label_value)) { bool label_is_i32 = value->ToInt32(&label_value);
UNREACHABLE(); DCHECK(value->IsNumber() && label_is_i32);
} (void)label_is_i32;
case_to_block[label_value] = i; case_to_block[label_value] = i;
cases.push_back(label_value); cases.push_back(label_value);
} else { } else {
...@@ -459,15 +455,15 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -459,15 +455,15 @@ class AsmWasmBuilderImpl : public AstVisitor {
void VisitFunctionLiteral(FunctionLiteral* expr) override { void VisitFunctionLiteral(FunctionLiteral* expr) override {
Scope* scope = expr->scope(); Scope* scope = expr->scope();
if (scope_ == kFuncScope) { if (scope_ == kFuncScope) {
if (bounds_->get(expr).lower->IsFunction()) { if (auto* func_type = typer_->TypeOf(expr)->AsFunctionType()) {
// Build the signature for the function. // Build the signature for the function.
FunctionType* func_type = bounds_->get(expr).lower->AsFunction(); LocalType return_type = TypeFrom(func_type->ReturnType());
LocalType return_type = TypeFrom(func_type->Result()); const auto& arguments = func_type->Arguments();
FunctionSig::Builder b(zone(), return_type == kAstStmt ? 0 : 1, FunctionSig::Builder b(zone(), return_type == kAstStmt ? 0 : 1,
func_type->Arity()); arguments.size());
if (return_type != kAstStmt) b.AddReturn(return_type); if (return_type != kAstStmt) b.AddReturn(return_type);
for (int i = 0; i < expr->parameter_count(); ++i) { for (int i = 0; i < expr->parameter_count(); ++i) {
LocalType type = TypeFrom(func_type->Parameter(i)); LocalType type = TypeFrom(arguments[i]);
DCHECK_NE(kAstStmt, type); DCHECK_NE(kAstStmt, type);
b.AddParam(type); b.AddParam(type);
InsertParameter(scope->parameter(i), type, i); InsertParameter(scope->parameter(i), type, i);
...@@ -573,15 +569,17 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -573,15 +569,17 @@ class AsmWasmBuilderImpl : public AstVisitor {
if (!value->IsNumber() || (scope_ != kFuncScope && scope_ != kInitScope)) { if (!value->IsNumber() || (scope_ != kFuncScope && scope_ != kInitScope)) {
return; return;
} }
Type* type = bounds_->get(expr).upper; AsmType* type = typer_->TypeOf(expr);
if (type->Is(cache_.kAsmSigned)) { DCHECK_NE(type, AsmType::None());
if (type->IsA(AsmType::Signed())) {
int32_t i = 0; int32_t i = 0;
if (!value->ToInt32(&i)) { if (!value->ToInt32(&i)) {
UNREACHABLE(); UNREACHABLE();
} }
byte code[] = {WASM_I32V(i)}; byte code[] = {WASM_I32V(i)};
current_function_builder_->EmitCode(code, sizeof(code)); current_function_builder_->EmitCode(code, sizeof(code));
} else if (type->Is(cache_.kAsmUnsigned) || type->Is(cache_.kAsmFixnum)) { } else if (type->IsA(AsmType::Unsigned()) || type->IsA(AsmType::FixNum())) {
uint32_t u = 0; uint32_t u = 0;
if (!value->ToUint32(&u)) { if (!value->ToUint32(&u)) {
UNREACHABLE(); UNREACHABLE();
...@@ -589,7 +587,7 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -589,7 +587,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
int32_t i = static_cast<int32_t>(u); int32_t i = static_cast<int32_t>(u);
byte code[] = {WASM_I32V(i)}; byte code[] = {WASM_I32V(i)};
current_function_builder_->EmitCode(code, sizeof(code)); current_function_builder_->EmitCode(code, sizeof(code));
} else if (type->Is(cache_.kAsmDouble)) { } else if (type->IsA(AsmType::Double())) {
double val = expr->raw_value()->AsNumber(); double val = expr->raw_value()->AsNumber();
byte code[] = {WASM_F64(val)}; byte code[] = {WASM_F64(val)};
current_function_builder_->EmitCode(code, sizeof(code)); current_function_builder_->EmitCode(code, sizeof(code));
...@@ -635,16 +633,18 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -635,16 +633,18 @@ class AsmWasmBuilderImpl : public AstVisitor {
} }
void AddFunctionTable(VariableProxy* table, ArrayLiteral* funcs) { void AddFunctionTable(VariableProxy* table, ArrayLiteral* funcs) {
FunctionType* func_type = auto* func_tbl_type = typer_->TypeOf(funcs)->AsFunctionTableType();
bounds_->get(funcs).lower->AsArray()->Element()->AsFunction(); DCHECK_NOT_NULL(func_tbl_type);
LocalType return_type = TypeFrom(func_type->Result()); auto* func_type = func_tbl_type->signature()->AsFunctionType();
const auto& arguments = func_type->Arguments();
LocalType return_type = TypeFrom(func_type->ReturnType());
FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1, FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1,
func_type->Arity()); arguments.size());
if (return_type != kAstStmt) { if (return_type != kAstStmt) {
sig.AddReturn(static_cast<LocalType>(return_type)); sig.AddReturn(return_type);
} }
for (int i = 0; i < func_type->Arity(); ++i) { for (auto* arg : arguments) {
sig.AddParam(TypeFrom(func_type->Parameter(i))); sig.AddParam(TypeFrom(arg));
} }
uint32_t signature_index = builder_->AddSignature(sig.Build()); uint32_t signature_index = builder_->AddSignature(sig.Build());
InsertFunctionTable(table->var(), next_table_index_, signature_index); InsertFunctionTable(table->var(), next_table_index_, signature_index);
...@@ -805,8 +805,8 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -805,8 +805,8 @@ class AsmWasmBuilderImpl : public AstVisitor {
if (target_prop != nullptr) { if (target_prop != nullptr) {
// Left hand side is a property access, i.e. the asm.js heap. // Left hand side is a property access, i.e. the asm.js heap.
if (TypeOf(expr->value()) == kAstF64 && expr->target()->IsProperty() && if (TypeOf(expr->value()) == kAstF64 && expr->target()->IsProperty() &&
bounds_->get(expr->target()->AsProperty()->obj()) typer_->TypeOf(expr->target()->AsProperty()->obj())
.lower->Is(cache_.kFloat32Array)) { ->IsA(AsmType::Float32Array())) {
current_function_builder_->Emit(kExprF32ConvertF64); current_function_builder_->Emit(kExprF32ConvertF64);
} }
WasmOpcode opcode; WasmOpcode opcode;
...@@ -846,7 +846,7 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -846,7 +846,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
if (vp != nullptr && vp->var()->IsParameter() && if (vp != nullptr && vp->var()->IsParameter() &&
vp->var()->index() == 1) { vp->var()->index() == 1) {
VariableProxy* target = expr->target()->AsVariableProxy(); VariableProxy* target = expr->target()->AsVariableProxy();
if (bounds_->get(target).lower->Is(Type::Function())) { if (typer_->TypeOf(target)->AsFFIType() != nullptr) {
const AstRawString* name = const AstRawString* name =
prop->key()->AsLiteral()->AsRawPropertyName(); prop->key()->AsLiteral()->AsRawPropertyName();
imported_function_table_.AddImport( imported_function_table_.AddImport(
...@@ -859,7 +859,10 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -859,7 +859,10 @@ class AsmWasmBuilderImpl : public AstVisitor {
} }
ArrayLiteral* funcs = expr->value()->AsArrayLiteral(); ArrayLiteral* funcs = expr->value()->AsArrayLiteral();
if (funcs != nullptr && if (funcs != nullptr &&
bounds_->get(funcs).lower->AsArray()->Element()->IsFunction()) { typer_->TypeOf(funcs)
->AsFunctionTableType()
->signature()
->AsFunctionType()) {
VariableProxy* target = expr->target()->AsVariableProxy(); VariableProxy* target = expr->target()->AsVariableProxy();
DCHECK_NOT_NULL(target); DCHECK_NOT_NULL(target);
AddFunctionTable(target, funcs); AddFunctionTable(target, funcs);
...@@ -905,34 +908,33 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -905,34 +908,33 @@ class AsmWasmBuilderImpl : public AstVisitor {
void VisitPropertyAndEmitIndex(Property* expr, MachineType* mtype) { void VisitPropertyAndEmitIndex(Property* expr, MachineType* mtype) {
Expression* obj = expr->obj(); Expression* obj = expr->obj();
DCHECK_EQ(bounds_->get(obj).lower, bounds_->get(obj).upper); AsmType* type = typer_->TypeOf(obj);
Type* type = bounds_->get(obj).lower;
int size; int size;
if (type->Is(cache_.kUint8Array)) { if (type->IsA(AsmType::Uint8Array())) {
*mtype = MachineType::Uint8(); *mtype = MachineType::Uint8();
size = 1; size = 1;
} else if (type->Is(cache_.kInt8Array)) { } else if (type->IsA(AsmType::Int8Array())) {
*mtype = MachineType::Int8(); *mtype = MachineType::Int8();
size = 1; size = 1;
} else if (type->Is(cache_.kUint16Array)) { } else if (type->IsA(AsmType::Uint16Array())) {
*mtype = MachineType::Uint16(); *mtype = MachineType::Uint16();
size = 2; size = 2;
} else if (type->Is(cache_.kInt16Array)) { } else if (type->IsA(AsmType::Int16Array())) {
*mtype = MachineType::Int16(); *mtype = MachineType::Int16();
size = 2; size = 2;
} else if (type->Is(cache_.kUint32Array)) { } else if (type->IsA(AsmType::Uint32Array())) {
*mtype = MachineType::Uint32(); *mtype = MachineType::Uint32();
size = 4; size = 4;
} else if (type->Is(cache_.kInt32Array)) { } else if (type->IsA(AsmType::Int32Array())) {
*mtype = MachineType::Int32(); *mtype = MachineType::Int32();
size = 4; size = 4;
} else if (type->Is(cache_.kUint32Array)) { } else if (type->IsA(AsmType::Uint32Array())) {
*mtype = MachineType::Uint32(); *mtype = MachineType::Uint32();
size = 4; size = 4;
} else if (type->Is(cache_.kFloat32Array)) { } else if (type->IsA(AsmType::Float32Array())) {
*mtype = MachineType::Float32(); *mtype = MachineType::Float32();
size = 4; size = 4;
} else if (type->Is(cache_.kFloat64Array)) { } else if (type->IsA(AsmType::Float64Array())) {
*mtype = MachineType::Float64(); *mtype = MachineType::Float64();
size = 8; size = 8;
} else { } else {
...@@ -1228,7 +1230,8 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -1228,7 +1230,8 @@ class AsmWasmBuilderImpl : public AstVisitor {
} }
} }
VisitCallArgs(call); VisitCallArgs(call);
switch (TypeIndexOf(args->at(0))) { static const bool kDontIgnoreSign = false;
switch (TypeIndexOf(args->at(0), kDontIgnoreSign)) {
case kInt32: case kInt32:
case kFixnum: case kFixnum:
current_function_builder_->Emit(kExprF32SConvertI32); current_function_builder_->Emit(kExprF32SConvertI32);
...@@ -1275,8 +1278,8 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -1275,8 +1278,8 @@ class AsmWasmBuilderImpl : public AstVisitor {
} }
uint32_t index; uint32_t index;
VariableProxy* vp = expr->expression()->AsVariableProxy(); VariableProxy* vp = expr->expression()->AsVariableProxy();
if (vp != nullptr && DCHECK_NOT_NULL(vp);
Type::Any()->Is(bounds_->get(vp).lower->AsFunction()->Result())) { if (typer_->TypeOf(vp)->AsFFIType() != nullptr) {
LocalType return_type = TypeOf(expr); LocalType return_type = TypeOf(expr);
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1, FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1,
...@@ -1479,9 +1482,10 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -1479,9 +1482,10 @@ class AsmWasmBuilderImpl : public AstVisitor {
void VisitBinaryOperation(BinaryOperation* expr) override { void VisitBinaryOperation(BinaryOperation* expr) override {
ConvertOperation convertOperation = MatchBinaryOperation(expr); ConvertOperation convertOperation = MatchBinaryOperation(expr);
static const bool kDontIgnoreSign = false;
if (convertOperation == kToDouble) { if (convertOperation == kToDouble) {
RECURSE(Visit(expr->left())); RECURSE(Visit(expr->left()));
TypeIndex type = TypeIndexOf(expr->left()); TypeIndex type = TypeIndexOf(expr->left(), kDontIgnoreSign);
if (type == kInt32 || type == kFixnum) { if (type == kInt32 || type == kFixnum) {
current_function_builder_->Emit(kExprF64SConvertI32); current_function_builder_->Emit(kExprF64SConvertI32);
} else if (type == kUint32) { } else if (type == kUint32) {
...@@ -1493,7 +1497,7 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -1493,7 +1497,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
} }
} else if (convertOperation == kToInt) { } else if (convertOperation == kToInt) {
RECURSE(Visit(GetLeft(expr))); RECURSE(Visit(GetLeft(expr)));
TypeIndex type = TypeIndexOf(GetLeft(expr)); TypeIndex type = TypeIndexOf(GetLeft(expr), kDontIgnoreSign);
if (type == kFloat32) { if (type == kFloat32) {
current_function_builder_->Emit(kExprI32AsmjsSConvertF32); current_function_builder_->Emit(kExprI32AsmjsSConvertF32);
} else if (type == kFloat64) { } else if (type == kFloat64) {
...@@ -1583,8 +1587,8 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -1583,8 +1587,8 @@ class AsmWasmBuilderImpl : public AstVisitor {
}; };
TypeIndex TypeIndexOf(Expression* left, Expression* right, bool ignore_sign) { TypeIndex TypeIndexOf(Expression* left, Expression* right, bool ignore_sign) {
TypeIndex left_index = TypeIndexOf(left); TypeIndex left_index = TypeIndexOf(left, ignore_sign);
TypeIndex right_index = TypeIndexOf(right); TypeIndex right_index = TypeIndexOf(right, ignore_sign);
if (left_index == kFixnum) { if (left_index == kFixnum) {
left_index = right_index; left_index = right_index;
} }
...@@ -1595,30 +1599,43 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -1595,30 +1599,43 @@ class AsmWasmBuilderImpl : public AstVisitor {
left_index = kInt32; left_index = kInt32;
right_index = kInt32; right_index = kInt32;
} }
DCHECK((left_index == right_index) || if (left_index != right_index) {
(ignore_sign && (left_index <= 1) && (right_index <= 1))); DCHECK(ignore_sign && (left_index <= 1) && (right_index <= 1));
}
return left_index; return left_index;
} }
TypeIndex TypeIndexOf(Expression* expr) { TypeIndex TypeIndexOf(Expression* expr, bool ignore_sign) {
DCHECK_EQ(bounds_->get(expr).lower, bounds_->get(expr).upper); AsmType* type = typer_->TypeOf(expr);
Type* type = bounds_->get(expr).lower; if (type->IsA(AsmType::FixNum())) {
if (type->Is(cache_.kAsmFixnum)) {
return kFixnum; return kFixnum;
} else if (type->Is(cache_.kAsmSigned)) { }
if (type->IsA(AsmType::Signed())) {
return kInt32; return kInt32;
} else if (type->Is(cache_.kAsmUnsigned)) { }
if (type->IsA(AsmType::Unsigned())) {
return kUint32; return kUint32;
} else if (type->Is(cache_.kAsmInt)) { }
if (type->IsA(AsmType::Intish())) {
if (!ignore_sign) {
// TODO(jpp): log a warning and move on.
}
return kInt32; return kInt32;
} else if (type->Is(cache_.kAsmFloat)) { }
if (type->IsA(AsmType::Floatish())) {
return kFloat32; return kFloat32;
} else if (type->Is(cache_.kAsmDouble)) { }
if (type->IsA(AsmType::DoubleQ())) {
return kFloat64; return kFloat64;
} else {
UNREACHABLE();
return kInt32;
} }
UNREACHABLE();
return kInt32;
} }
#undef CASE #undef CASE
...@@ -1721,21 +1738,22 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -1721,21 +1738,22 @@ class AsmWasmBuilderImpl : public AstVisitor {
return (reinterpret_cast<IndexContainer*>(entry->value))->index; return (reinterpret_cast<IndexContainer*>(entry->value))->index;
} }
LocalType TypeOf(Expression* expr) { LocalType TypeOf(Expression* expr) { return TypeFrom(typer_->TypeOf(expr)); }
DCHECK_EQ(bounds_->get(expr).lower, bounds_->get(expr).upper);
return TypeFrom(bounds_->get(expr).lower);
}
LocalType TypeFrom(Type* type) { LocalType TypeFrom(AsmType* type) {
if (type->Is(cache_.kAsmInt)) { if (type->IsA(AsmType::Intish())) {
return kAstI32; return kAstI32;
} else if (type->Is(cache_.kAsmFloat)) { }
if (type->IsA(AsmType::Floatish())) {
return kAstF32; return kAstF32;
} else if (type->Is(cache_.kAsmDouble)) { }
if (type->IsA(AsmType::DoubleQ())) {
return kAstF64; return kAstF64;
} else {
return kAstStmt;
} }
return kAstStmt;
} }
Zone* zone() { return zone_; } Zone* zone() { return zone_; }
...@@ -1750,7 +1768,6 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -1750,7 +1768,6 @@ class AsmWasmBuilderImpl : public AstVisitor {
Isolate* isolate_; Isolate* isolate_;
Zone* zone_; Zone* zone_;
AsmTyper* typer_; AsmTyper* typer_;
TypeCache const& cache_;
ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_; ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_;
ZoneVector<ForeignVariable> foreign_variables_; ZoneVector<ForeignVariable> foreign_variables_;
uint32_t init_function_index_; uint32_t init_function_index_;
...@@ -1758,7 +1775,6 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -1758,7 +1775,6 @@ class AsmWasmBuilderImpl : public AstVisitor {
uint32_t next_table_index_; uint32_t next_table_index_;
ZoneHashMap function_tables_; ZoneHashMap function_tables_;
ImportedFunctionTable imported_function_table_; ImportedFunctionTable imported_function_table_;
const AstTypeBounds* bounds_;
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#define V8_ASMJS_ASM_WASM_BUILDER_H_ #define V8_ASMJS_ASM_WASM_BUILDER_H_
#include "src/allocation.h" #include "src/allocation.h"
#include "src/asmjs/typing-asm.h" #include "src/asmjs/asm-typer.h"
#include "src/objects.h" #include "src/objects.h"
#include "src/wasm/encoder.h" #include "src/wasm/encoder.h"
#include "src/zone.h" #include "src/zone.h"
......
...@@ -504,7 +504,6 @@ DEFINE_BOOL(wasm_loop_assignment_analysis, true, ...@@ -504,7 +504,6 @@ DEFINE_BOOL(wasm_loop_assignment_analysis, true,
"perform loop assignment analysis for WASM") "perform loop assignment analysis for WASM")
DEFINE_BOOL(validate_asm, false, "validate asm.js modules before compiling") DEFINE_BOOL(validate_asm, false, "validate asm.js modules before compiling")
DEFINE_BOOL(enable_simd_asmjs, false, "enable SIMD.js in asm.js stdlib")
DEFINE_BOOL(dump_wasm_module, false, "dump WASM module bytes") DEFINE_BOOL(dump_wasm_module, false, "dump WASM module bytes")
DEFINE_STRING(dump_wasm_module_path, NULL, "directory to dump wasm modules to") DEFINE_STRING(dump_wasm_module_path, NULL, "directory to dump wasm modules to")
......
...@@ -149,11 +149,8 @@ v8::internal::wasm::ZoneBuffer* TranslateAsmModule( ...@@ -149,11 +149,8 @@ v8::internal::wasm::ZoneBuffer* TranslateAsmModule(
info->set_literal( info->set_literal(
info->scope()->declarations()->at(0)->AsFunctionDeclaration()->fun()); info->scope()->declarations()->at(0)->AsFunctionDeclaration()->fun());
v8::internal::AsmTyper typer(info->isolate(), info->zone(), *(info->script()), v8::internal::wasm::AsmTyper typer(info->isolate(), info->zone(),
info->literal()); *(info->script()), info->literal());
if (i::FLAG_enable_simd_asmjs) {
typer.set_allow_simd(true);
}
if (!typer.Validate()) { if (!typer.Validate()) {
thrower->Error("Asm.js validation failed: %s", typer.error_message()); thrower->Error("Asm.js validation failed: %s", typer.error_message());
return nullptr; return nullptr;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
// Flags: --expose-wasm // Flags: --expose-wasm
function __f_61(stdlib, buffer) { function __f_61(stdlib, foreign, buffer) {
"use asm"; "use asm";
var __v_14 = new stdlib.Float64Array(buffer); var __v_14 = new stdlib.Float64Array(buffer);
function __f_74() { function __f_74() {
......
...@@ -83,33 +83,34 @@ ...@@ -83,33 +83,34 @@
} }
function caller() { function caller() {
if (!deltaEqual(StdlibMathSqrt(123.0), 11.090536506409418)) return 0; if (!(deltaEqual(+StdlibMathSqrt(123.0), 11.090536506409418)|0)) return 0;
if (StdlibMathSqrt(fround(256.0)) != fround(16.0)) return 0; if (fround(StdlibMathSqrt(fround(256.0))) != fround(16.0)) return 0;
if (StdlibMathCeil(123.7) != 124.0) return 0; if (+StdlibMathCeil(123.7) != 124.0) return 0;
if (StdlibMathCeil(fround(123.7)) != fround(124.0)) return 0; if (fround(StdlibMathCeil(fround(123.7))) != fround(124.0)) return 0;
if (StdlibMathFloor(123.7) != 123.0) return 0; if (+StdlibMathFloor(123.7) != 123.0) return 0;
if (StdlibMathFloor(fround(123.7)) != fround(123.0)) return 0; if (fround(StdlibMathFloor(fround(123.7))) != fround(123.0)) return 0;
if (StdlibMathAbs(-123.0) != 123.0) return 0; if (+StdlibMathAbs(-123.0) != 123.0) return 0;
if (StdlibMathAbs(fround(-123.0)) != fround(123.0)) return 0; if (fround(StdlibMathAbs(fround(-123.0))) != fround(123.0)) return 0;
if (StdlibMathMin(123.4, 1236.4) != 123.4) return 0; if (+StdlibMathMin(123.4, 1236.4) != 123.4) return 0;
if (StdlibMathMin(fround(123.4), if (fround(StdlibMathMin(fround(123.4),
fround(1236.4)) != fround(123.4)) return 0; fround(1236.4))) != fround(123.4)) return 0;
if (StdlibMathMax(123.4, 1236.4) != 1236.4) return 0; if (+StdlibMathMax(123.4, 1236.4) != 1236.4) return 0;
if (StdlibMathMax(fround(123.4), fround(1236.4)) if (fround(StdlibMathMax(fround(123.4), fround(1236.4)))
!= fround(1236.4)) return 0; != fround(1236.4)) return 0;
if (!deltaEqual(StdlibMathAcos(0.1), 1.4706289056333368)) return 0; if (!(deltaEqual(+StdlibMathAcos(0.1), 1.4706289056333368)|0)) return 0;
if (!deltaEqual(StdlibMathAsin(0.2), 0.2013579207903308)) return 0; if (!(deltaEqual(+StdlibMathAsin(0.2), 0.2013579207903308)|0)) return 0;
if (!deltaEqual(StdlibMathAtan(0.2), 0.19739555984988078)) return 0; if (!(deltaEqual(+StdlibMathAtan(0.2), 0.19739555984988078)|0)) return 0;
if (!deltaEqual(StdlibMathCos(0.2), 0.9800665778412416)) return 0; if (!(deltaEqual(+StdlibMathCos(0.2), 0.9800665778412416)|0)) return 0;
if (!deltaEqual(StdlibMathSin(0.2), 0.19866933079506122)) return 0; if (!(deltaEqual(+StdlibMathSin(0.2), 0.19866933079506122)|0)) return 0;
if (!deltaEqual(StdlibMathTan(0.2), 0.20271003550867250)) return 0; if (!(deltaEqual(+StdlibMathTan(0.2), 0.20271003550867250)|0)) return 0;
if (!deltaEqual(StdlibMathExp(0.2), 1.2214027581601699)) return 0; if (!(deltaEqual(+StdlibMathExp(0.2), 1.2214027581601699)|0)) return 0;
if (!deltaEqual(StdlibMathLog(0.2), -1.6094379124341003)) return 0; if (!(deltaEqual(+StdlibMathLog(0.2), -1.6094379124341003)|0)) return 0;
if (StdlibMathImul(6, 7) != 42) return 0; if ((StdlibMathImul(6, 7)|0) != 42) return 0;
if (!deltaEqual(StdlibMathAtan2(6.0, 7.0), 0.7086262721276703)) return 0; if (!(deltaEqual(+StdlibMathAtan2(6.0, 7.0), 0.7086262721276703)|0))
if (StdlibMathPow(6.0, 7.0) != 279936.0) return 0; return 0;
if (+StdlibMathPow(6.0, 7.0) != 279936.0) return 0;
return 1; return 1;
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
function caller() { function caller() {
var ret = 0; var ret = 0;
var x = 7; var x = 7;
switch (x) { switch (x|0) {
case 1: { case 1: {
return 0; return 0;
} }
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
function caller() { function caller() {
var ret = 0; var ret = 0;
var x = 7; var x = 7;
switch (x) { switch (x|0) {
case 1: return 0; case 1: return 0;
case 7: { case 7: {
ret = 12; ret = 12;
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
} }
default: return 0; default: return 0;
} }
switch (x) { switch (x|0) {
case 1: return 0; case 1: return 0;
case 8: return 0; case 8: return 0;
default: ret = (ret + 11)|0; default: ret = (ret + 11)|0;
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
function caller() { function caller() {
var x = 17; var x = 17;
var ret = 0; var ret = 0;
switch (x) { switch (x|0) {
case 17: case 17:
case 14: ret = 39; case 14: ret = 39;
case 1: ret = (ret + 3)|0; case 1: ret = (ret + 3)|0;
...@@ -89,10 +89,10 @@ ...@@ -89,10 +89,10 @@
function caller() { function caller() {
var x = 3; var x = 3;
var y = -13; var y = -13;
switch (x) { switch (x|0) {
case 1: return 0; case 1: return 0;
case 3: { case 3: {
switch (y) { switch (y|0) {
case 2: return 0; case 2: return 0;
case -13: return 43; case -13: return 43;
default: return 0; default: return 0;
......
...@@ -43,9 +43,11 @@ function IntTest() { ...@@ -43,9 +43,11 @@ function IntTest() {
function sum(a, b) { function sum(a, b) {
a = a|0; a = a|0;
b = b|0; b = b|0;
var c = (b + 1)|0 var c = 0;
var d = 3.0; var d = 3.0;
var e = ~~d; // double conversion var e = 0;
e = ~~d; // double conversion
c = (b + 1)|0
return (a + c + 1)|0; return (a + c + 1)|0;
} }
...@@ -68,8 +70,9 @@ function Float64Test() { ...@@ -68,8 +70,9 @@ function Float64Test() {
} }
function caller() { function caller() {
var a = +sum(70.1,10.2); var a = 0.0;
var ret = 0|0; var ret = 0|0;
a = +sum(70.1,10.2);
if (a == 80.3) { if (a == 80.3) {
ret = 1|0; ret = 1|0;
} else { } else {
...@@ -89,7 +92,8 @@ function BadModule() { ...@@ -89,7 +92,8 @@ function BadModule() {
function caller(a, b) { function caller(a, b) {
a = a|0; a = a|0;
b = b+0; b = b+0;
var c = (b + 1)|0 var c = 0;
c = (b + 1)|0
return (a + c + 1)|0; return (a + c + 1)|0;
} }
...@@ -293,12 +297,12 @@ function TestBreakInNestedWhile() { ...@@ -293,12 +297,12 @@ function TestBreakInNestedWhile() {
function caller() { function caller() {
var x = 1.0; var x = 1.0;
var ret = 0;
while(x < 1.5) { while(x < 1.5) {
while(1) while(1)
break; break;
x = +(x + 0.25); x = +(x + 0.25);
} }
var ret = 0;
if (x == 1.5) { if (x == 1.5) {
ret = 9; ret = 9;
} }
...@@ -405,7 +409,8 @@ function TestNot() { ...@@ -405,7 +409,8 @@ function TestNot() {
"use asm"; "use asm";
function caller() { function caller() {
var a = !(2 > 3); var a = 0;
a = !(2 > 3);
return a | 0; return a | 0;
} }
...@@ -886,7 +891,9 @@ function TestFunctionTableSingleFunction() { ...@@ -886,7 +891,9 @@ function TestFunctionTableSingleFunction() {
} }
function caller() { function caller() {
return function_table[0&0]() | 0; // TODO(jpp): the parser optimizes function_table[0&0] to function table[0].
var v = 0;
return function_table[v&0]() | 0;
} }
var function_table = [dummy] var function_table = [dummy]
...@@ -911,8 +918,9 @@ function TestFunctionTableMultipleFunctions() { ...@@ -911,8 +918,9 @@ function TestFunctionTableMultipleFunctions() {
} }
function caller() { function caller() {
if ((function_table[0&1](50)|0) == 51) { var i = 0, j = 1;
if ((function_table[1&1](60)|0) == 62) { if ((function_table[i&1](50)|0) == 51) {
if ((function_table[j&1](60)|0) == 62) {
return 73; return 73;
} }
} }
...@@ -1350,7 +1358,7 @@ assertWasm(1, TestXor); ...@@ -1350,7 +1358,7 @@ assertWasm(1, TestXor);
"use asm"; "use asm";
function func() { function func() {
var a = 1; var a = 1;
return ((a * 3) + (4 * a)) | 0; return (((a * 3)|0) + ((4 * a)|0)) | 0;
} }
return {func: func}; return {func: func};
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment