LCOV - code coverage report
Current view: top level - src/asmjs - asm-js.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 126 137 92.0 %
Date: 2017-04-26 Functions: 5 5 100.0 %

          Line data    Source code
       1             : // Copyright 2015 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/asmjs/asm-js.h"
       6             : 
       7             : #include "src/api-natives.h"
       8             : #include "src/api.h"
       9             : #include "src/asmjs/asm-names.h"
      10             : #include "src/asmjs/asm-parser.h"
      11             : #include "src/asmjs/asm-typer.h"
      12             : #include "src/asmjs/asm-wasm-builder.h"
      13             : #include "src/assert-scope.h"
      14             : #include "src/base/platform/elapsed-timer.h"
      15             : #include "src/compilation-info.h"
      16             : #include "src/execution.h"
      17             : #include "src/factory.h"
      18             : #include "src/handles.h"
      19             : #include "src/isolate.h"
      20             : #include "src/objects-inl.h"
      21             : #include "src/objects.h"
      22             : 
      23             : #include "src/wasm/module-decoder.h"
      24             : #include "src/wasm/wasm-js.h"
      25             : #include "src/wasm/wasm-module-builder.h"
      26             : #include "src/wasm/wasm-module.h"
      27             : #include "src/wasm/wasm-objects.h"
      28             : #include "src/wasm/wasm-result.h"
      29             : 
      30             : namespace v8 {
      31             : namespace internal {
      32             : 
      33             : namespace {
      34             : enum WasmDataEntries {
      35             :   kWasmDataCompiledModule,
      36             :   kWasmDataForeignGlobals,
      37             :   kWasmDataUsesArray,
      38             :   kWasmDataScript,
      39             :   kWasmDataScriptPosition,
      40             :   kWasmDataEntryCount,
      41             : };
      42             : 
      43       14434 : Handle<Object> StdlibMathMember(Isolate* isolate, Handle<JSReceiver> stdlib,
      44             :                                 Handle<Name> name) {
      45       14434 :   if (stdlib.is_null()) {
      46           0 :     return Handle<Object>();
      47             :   }
      48             :   Handle<Name> math_name(
      49       28868 :       isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("Math")));
      50       14434 :   MaybeHandle<Object> maybe_math = Object::GetProperty(stdlib, math_name);
      51       14434 :   if (maybe_math.is_null()) {
      52           0 :     return Handle<Object>();
      53             :   }
      54             :   Handle<Object> math = maybe_math.ToHandleChecked();
      55       14434 :   if (!math->IsJSReceiver()) {
      56         216 :     return Handle<Object>();
      57             :   }
      58       14218 :   MaybeHandle<Object> maybe_value = Object::GetProperty(math, name);
      59       14218 :   if (maybe_value.is_null()) {
      60           0 :     return Handle<Object>();
      61             :   }
      62             :   return maybe_value.ToHandleChecked();
      63             : }
      64             : 
      65       16704 : bool IsStdlibMemberValid(Isolate* isolate, Handle<JSReceiver> stdlib,
      66             :                          Handle<Object> member_id) {
      67             :   int32_t member_kind;
      68       16704 :   if (!member_id->ToInt32(&member_kind)) {
      69           0 :     UNREACHABLE();
      70             :   }
      71       16704 :   switch (static_cast<wasm::AsmTyper::StandardMember>(member_kind)) {
      72             :     case wasm::AsmTyper::StandardMember::kNone:
      73             :     case wasm::AsmTyper::StandardMember::kModule:
      74             :     case wasm::AsmTyper::StandardMember::kStdlib:
      75             :     case wasm::AsmTyper::StandardMember::kHeap:
      76             :     case wasm::AsmTyper::StandardMember::kFFI: {
      77             :       // Nothing to check for these.
      78             :       return true;
      79             :     }
      80             :     case wasm::AsmTyper::StandardMember::kInfinity: {
      81          31 :       if (stdlib.is_null()) {
      82             :         return false;
      83             :       }
      84             :       Handle<Name> name(isolate->factory()->InternalizeOneByteString(
      85          62 :           STATIC_CHAR_VECTOR("Infinity")));
      86          31 :       MaybeHandle<Object> maybe_value = Object::GetProperty(stdlib, name);
      87          31 :       if (maybe_value.is_null()) {
      88             :         return false;
      89             :       }
      90             :       Handle<Object> value = maybe_value.ToHandleChecked();
      91          54 :       return value->IsNumber() && std::isinf(value->Number());
      92             :     }
      93             :     case wasm::AsmTyper::StandardMember::kNaN: {
      94          85 :       if (stdlib.is_null()) {
      95             :         return false;
      96             :       }
      97             :       Handle<Name> name(isolate->factory()->InternalizeOneByteString(
      98          90 :           STATIC_CHAR_VECTOR("NaN")));
      99          45 :       MaybeHandle<Object> maybe_value = Object::GetProperty(stdlib, name);
     100          45 :       if (maybe_value.is_null()) {
     101             :         return false;
     102             :       }
     103             :       Handle<Object> value = maybe_value.ToHandleChecked();
     104          45 :       return value->IsNaN();
     105             :     }
     106             : #define STDLIB_MATH_FUNC(fname, FName, ignore1, ignore2)            \
     107             :   case wasm::AsmTyper::StandardMember::kMath##FName: {              \
     108             :     Handle<Name> name(isolate->factory()->InternalizeOneByteString( \
     109             :         STATIC_CHAR_VECTOR(#fname)));                               \
     110             :     Handle<Object> value = StdlibMathMember(isolate, stdlib, name); \
     111             :     if (value.is_null() || !value->IsJSFunction()) {                \
     112             :       return false;                                                 \
     113             :     }                                                               \
     114             :     Handle<JSFunction> func(JSFunction::cast(*value));              \
     115             :     return func->shared()->code() ==                                \
     116             :            isolate->builtins()->builtin(Builtins::kMath##FName);    \
     117             :   }
     118       56288 :       STDLIB_MATH_FUNCTION_LIST(STDLIB_MATH_FUNC)
     119             : #undef STDLIB_MATH_FUNC
     120             : #define STDLIB_MATH_CONST(cname, const_value)                       \
     121             :   case wasm::AsmTyper::StandardMember::kMath##cname: {              \
     122             :     Handle<Name> name(isolate->factory()->InternalizeOneByteString( \
     123             :         STATIC_CHAR_VECTOR(#cname)));                               \
     124             :     Handle<Object> value = StdlibMathMember(isolate, stdlib, name); \
     125             :     return !value.is_null() && value->IsNumber() &&                 \
     126             :            value->Number() == const_value;                          \
     127             :   }
     128         864 :       STDLIB_MATH_VALUE_LIST(STDLIB_MATH_CONST)
     129             : #undef STDLIB_MATH_CONST
     130             : #define STDLIB_ARRAY_TYPE(fname, FName)                                  \
     131             :   case wasm::AsmTyper::StandardMember::k##FName: {                       \
     132             :     if (stdlib.is_null()) {                                              \
     133             :       return false;                                                      \
     134             :     }                                                                    \
     135             :     Handle<Name> name(isolate->factory()->InternalizeOneByteString(      \
     136             :         STATIC_CHAR_VECTOR(#FName)));                                    \
     137             :     Handle<Object> value;                                                \
     138             :     MaybeHandle<Object> maybe_value = Object::GetProperty(stdlib, name); \
     139             :     if (!maybe_value.ToHandle(&value) || !value->IsJSFunction()) {       \
     140             :       return false;                                                      \
     141             :     }                                                                    \
     142             :     Handle<JSFunction> func = Handle<JSFunction>::cast(value);           \
     143             :     return func.is_identical_to(isolate->fname());                       \
     144             :   }
     145         112 :       STDLIB_ARRAY_TYPE(int8_array_fun, Int8Array)
     146         105 :       STDLIB_ARRAY_TYPE(uint8_array_fun, Uint8Array)
     147          98 :       STDLIB_ARRAY_TYPE(int16_array_fun, Int16Array)
     148          84 :       STDLIB_ARRAY_TYPE(uint16_array_fun, Uint16Array)
     149         896 :       STDLIB_ARRAY_TYPE(int32_array_fun, Int32Array)
     150          84 :       STDLIB_ARRAY_TYPE(uint32_array_fun, Uint32Array)
     151         182 :       STDLIB_ARRAY_TYPE(float32_array_fun, Float32Array)
     152         119 :       STDLIB_ARRAY_TYPE(float64_array_fun, Float64Array)
     153             : #undef STDLIB_ARRAY_TYPE
     154             :   }
     155           0 :   UNREACHABLE();
     156             :   return false;
     157             : }
     158             : 
     159             : }  // namespace
     160             : 
     161     1087847 : MaybeHandle<FixedArray> AsmJs::CompileAsmViaWasm(CompilationInfo* info) {
     162       10848 :   wasm::ZoneBuffer* module = nullptr;
     163        3616 :   wasm::ZoneBuffer* asm_offsets = nullptr;
     164             :   Handle<FixedArray> uses_array;
     165             :   Handle<FixedArray> foreign_globals;
     166             :   base::ElapsedTimer asm_wasm_timer;
     167             :   asm_wasm_timer.Start();
     168      354696 :   wasm::AsmWasmBuilder builder(info);
     169      354695 :   size_t asm_wasm_zone_start = info->zone()->allocation_size();
     170      354695 :   if (FLAG_fast_validate_asm) {
     171             :     wasm::AsmJsParser parser(info->isolate(), info->zone(), info->script(),
     172             :                              info->literal()->start_position(),
     173      702327 :                              info->literal()->end_position());
     174      351164 :     if (!parser.Run()) {
     175             :       DCHECK(!info->isolate()->has_pending_exception());
     176      350615 :       if (!FLAG_suppress_asm_messages) {
     177             :         MessageLocation location(info->script(), parser.failure_location(),
     178         139 :                                  parser.failure_location());
     179             :         Handle<String> message =
     180             :             info->isolate()
     181             :                 ->factory()
     182             :                 ->NewStringFromUtf8(CStrVector(parser.failure_message()))
     183         417 :                 .ToHandleChecked();
     184             :         Handle<JSMessageObject> error_message =
     185             :             MessageHandler::MakeMessageObject(
     186             :                 info->isolate(), MessageTemplate::kAsmJsInvalid, &location,
     187         139 :                 message, Handle<FixedArray>::null());
     188             :         error_message->set_error_level(v8::Isolate::kMessageWarning);
     189             :         MessageHandler::ReportMessage(info->isolate(), &location,
     190         139 :                                       error_message);
     191             :       }
     192      350615 :       return MaybeHandle<FixedArray>();
     193             :     }
     194             :     Zone* zone = info->zone();
     195             :     module = new (zone) wasm::ZoneBuffer(zone);
     196         549 :     parser.module_builder()->WriteTo(*module);
     197             :     asm_offsets = new (zone) wasm::ZoneBuffer(zone);
     198         549 :     parser.module_builder()->WriteAsmJsOffsetTable(*asm_offsets);
     199             :     // TODO(bradnelson): Remove foreign_globals plumbing (as we don't need it
     200             :     // for the new parser).
     201         549 :     foreign_globals = info->isolate()->factory()->NewFixedArray(0);
     202             :     uses_array = info->isolate()->factory()->NewFixedArray(
     203        1098 :         static_cast<int>(parser.stdlib_uses()->size()));
     204             :     int count = 0;
     205        2309 :     for (auto i : *parser.stdlib_uses()) {
     206        1211 :       uses_array->set(count++, Smi::FromInt(i));
     207         549 :     }
     208             :   } else {
     209        3532 :     auto asm_wasm_result = builder.Run(&foreign_globals);
     210        3532 :     if (!asm_wasm_result.success) {
     211             :       DCHECK(!info->isolate()->has_pending_exception());
     212         465 :       if (!FLAG_suppress_asm_messages) {
     213             :         MessageHandler::ReportMessage(info->isolate(),
     214             :                                       builder.typer()->message_location(),
     215         465 :                                       builder.typer()->error_message());
     216             :       }
     217         465 :       return MaybeHandle<FixedArray>();
     218             :     }
     219        3067 :     module = asm_wasm_result.module_bytes;
     220        3067 :     asm_offsets = asm_wasm_result.asm_offset_table;
     221             :     wasm::AsmTyper::StdlibSet uses = builder.typer()->StdlibUses();
     222             :     uses_array = info->isolate()->factory()->NewFixedArray(
     223        6134 :         static_cast<int>(uses.size()));
     224             :     int count = 0;
     225       14434 :     for (auto i : uses) {
     226        8300 :       uses_array->set(count++, Smi::FromInt(i));
     227             :     }
     228             :   }
     229             : 
     230        3616 :   double asm_wasm_time = asm_wasm_timer.Elapsed().InMillisecondsF();
     231        3616 :   size_t asm_wasm_zone = info->zone()->allocation_size() - asm_wasm_zone_start;
     232        3616 :   if (FLAG_trace_asm_parser) {
     233             :     PrintF("[asm.js translation successful: time=%0.3fms, zone=%" PRIuS "KB]\n",
     234           0 :            asm_wasm_time, asm_wasm_zone / KB);
     235             :   }
     236             : 
     237             :   Vector<const byte> asm_offsets_vec(asm_offsets->begin(),
     238        3616 :                                      static_cast<int>(asm_offsets->size()));
     239             : 
     240             :   base::ElapsedTimer compile_timer;
     241             :   compile_timer.Start();
     242             :   wasm::ErrorThrower thrower(info->isolate(),
     243        3616 :                              "Asm.js -> WebAssembly conversion");
     244             :   MaybeHandle<JSObject> compiled = SyncCompileTranslatedAsmJs(
     245             :       info->isolate(), &thrower,
     246             :       wasm::ModuleWireBytes(module->begin(), module->end()), info->script(),
     247       10848 :       asm_offsets_vec);
     248             :   DCHECK(!compiled.is_null());
     249             :   DCHECK(!thrower.error());
     250        3616 :   double compile_time = compile_timer.Elapsed().InMillisecondsF();
     251             :   DCHECK_GE(module->end(), module->begin());
     252        7232 :   uintptr_t wasm_size = module->end() - module->begin();
     253             : 
     254             :   Handle<FixedArray> result =
     255        3616 :       info->isolate()->factory()->NewFixedArray(kWasmDataEntryCount);
     256        3616 :   result->set(kWasmDataCompiledModule, *compiled.ToHandleChecked());
     257        3616 :   result->set(kWasmDataForeignGlobals, *foreign_globals);
     258        3616 :   result->set(kWasmDataUsesArray, *uses_array);
     259        7232 :   result->set(kWasmDataScript, *info->script());
     260             :   result->set(kWasmDataScriptPosition,
     261        3616 :               Smi::FromInt(info->literal()->position()));
     262             : 
     263        3616 :   MessageLocation location(info->script(), info->literal()->position(),
     264        7232 :                            info->literal()->position());
     265             :   char text[100];
     266             :   int length;
     267        3616 :   if (FLAG_predictable) {
     268           0 :     length = base::OS::SNPrintF(text, arraysize(text), "success");
     269             :   } else {
     270             :     length = base::OS::SNPrintF(
     271             :         text, arraysize(text),
     272             :         "success, asm->wasm: %0.3f ms, compile: %0.3f ms, %" PRIuPTR " bytes",
     273        3616 :         asm_wasm_time, compile_time, wasm_size);
     274             :   }
     275             :   DCHECK_NE(-1, length);
     276             :   USE(length);
     277        3616 :   Handle<String> stext(info->isolate()->factory()->InternalizeUtf8String(text));
     278             :   Handle<JSMessageObject> message = MessageHandler::MakeMessageObject(
     279             :       info->isolate(), MessageTemplate::kAsmJsCompiled, &location, stext,
     280        3616 :       Handle<FixedArray>::null());
     281             :   message->set_error_level(v8::Isolate::kMessageInfo);
     282        3616 :   if (!FLAG_suppress_asm_messages && FLAG_trace_asm_time) {
     283           0 :     MessageHandler::ReportMessage(info->isolate(), &location, message);
     284             :   }
     285             : 
     286             :   return result;
     287             : }
     288             : 
     289        6994 : bool AsmJs::IsStdlibValid(Isolate* isolate, Handle<FixedArray> wasm_data,
     290             :                           Handle<JSReceiver> stdlib) {
     291             :   Handle<FixedArray> uses(FixedArray::cast(wasm_data->get(kWasmDataUsesArray)));
     292       46386 :   for (int i = 0; i < uses->length(); ++i) {
     293       16704 :     if (!IsStdlibMemberValid(isolate, stdlib,
     294       16704 :                              uses->GetValueChecked<Object>(isolate, i))) {
     295             :       return false;
     296             :     }
     297             :   }
     298             :   return true;
     299             : }
     300             : 
     301        6489 : MaybeHandle<Object> AsmJs::InstantiateAsmWasm(Isolate* isolate,
     302             :                                               Handle<FixedArray> wasm_data,
     303             :                                               Handle<JSArrayBuffer> memory,
     304             :                                               Handle<JSReceiver> foreign) {
     305             :   base::ElapsedTimer instantiate_timer;
     306             :   instantiate_timer.Start();
     307             :   Handle<WasmModuleObject> module(
     308        6489 :       WasmModuleObject::cast(wasm_data->get(kWasmDataCompiledModule)));
     309             :   Handle<FixedArray> foreign_globals(
     310             :       FixedArray::cast(wasm_data->get(kWasmDataForeignGlobals)));
     311             : 
     312             :   // Create the ffi object for foreign functions {"": foreign}.
     313             :   Handle<JSObject> ffi_object;
     314        6489 :   if (!foreign.is_null()) {
     315             :     Handle<JSFunction> object_function = Handle<JSFunction>(
     316        5076 :         isolate->native_context()->object_function(), isolate);
     317        2538 :     ffi_object = isolate->factory()->NewJSObject(object_function);
     318             :     JSObject::AddProperty(ffi_object, isolate->factory()->empty_string(),
     319        2538 :                           foreign, NONE);
     320             :   }
     321             : 
     322             :   wasm::ErrorThrower thrower(isolate, "Asm.js -> WebAssembly instantiation");
     323             :   MaybeHandle<Object> maybe_module_object =
     324       12978 :       wasm::SyncInstantiate(isolate, &thrower, module, ffi_object, memory);
     325        6489 :   if (maybe_module_object.is_null()) {
     326             :     thrower.Reify();  // Ensure exceptions do not propagate.
     327             :     return MaybeHandle<Object>();
     328             :   }
     329             :   DCHECK(!thrower.error());
     330        6487 :   Handle<Object> module_object = maybe_module_object.ToHandleChecked();
     331             : 
     332        6487 :   if (!FLAG_fast_validate_asm) {
     333             :     Handle<Name> init_name(isolate->factory()->InternalizeUtf8String(
     334        5796 :         wasm::AsmWasmBuilder::foreign_init_name));
     335             :     Handle<Object> init =
     336       11592 :         Object::GetProperty(module_object, init_name).ToHandleChecked();
     337             : 
     338        5796 :     Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
     339             :     Handle<Object>* foreign_args_array =
     340        7558 :         new Handle<Object>[foreign_globals->length()];
     341        9320 :     for (int j = 0; j < foreign_globals->length(); j++) {
     342        1762 :       if (!foreign.is_null()) {
     343             :         MaybeHandle<Name> name = Object::ToName(
     344        1750 :             isolate, Handle<Object>(foreign_globals->get(j), isolate));
     345        1750 :         if (!name.is_null()) {
     346             :           MaybeHandle<Object> val =
     347        1750 :               Object::GetProperty(foreign, name.ToHandleChecked());
     348        1750 :           if (!val.is_null()) {
     349        3500 :             foreign_args_array[j] = val.ToHandleChecked();
     350             :             continue;
     351             :           }
     352             :         }
     353             :       }
     354          12 :       foreign_args_array[j] = undefined;
     355             :     }
     356             :     MaybeHandle<Object> retval =
     357             :         Execution::Call(isolate, init, undefined, foreign_globals->length(),
     358        5796 :                         foreign_args_array);
     359        5796 :     delete[] foreign_args_array;
     360             :     DCHECK(!retval.is_null());
     361             :   }
     362             : 
     363             :   Handle<Name> single_function_name(isolate->factory()->InternalizeUtf8String(
     364        6487 :       wasm::AsmWasmBuilder::single_function_name));
     365             :   MaybeHandle<Object> single_function =
     366        6487 :       Object::GetProperty(module_object, single_function_name);
     367       12974 :   if (!single_function.is_null() &&
     368             :       !single_function.ToHandleChecked()->IsUndefined(isolate)) {
     369         254 :     return single_function;
     370             :   }
     371             : 
     372             :   Handle<Script> script(Script::cast(wasm_data->get(kWasmDataScript)));
     373        6233 :   int32_t position = 0;
     374        6233 :   if (!wasm_data->get(kWasmDataScriptPosition)->ToInt32(&position)) {
     375           0 :     UNREACHABLE();
     376             :   }
     377        6233 :   MessageLocation location(script, position, position);
     378             :   char text[50];
     379             :   int length;
     380        6233 :   if (FLAG_predictable) {
     381           0 :     length = base::OS::SNPrintF(text, arraysize(text), "success");
     382             :   } else {
     383             :     length = base::OS::SNPrintF(text, arraysize(text), "success, %0.3f ms",
     384        6233 :                                 instantiate_timer.Elapsed().InMillisecondsF());
     385             :   }
     386             :   DCHECK_NE(-1, length);
     387             :   USE(length);
     388        6233 :   Handle<String> stext(isolate->factory()->InternalizeUtf8String(text));
     389             :   Handle<JSMessageObject> message = MessageHandler::MakeMessageObject(
     390             :       isolate, MessageTemplate::kAsmJsInstantiated, &location, stext,
     391        6233 :       Handle<FixedArray>::null());
     392             :   message->set_error_level(v8::Isolate::kMessageInfo);
     393        6233 :   if (!FLAG_suppress_asm_messages && FLAG_trace_asm_time) {
     394           0 :     MessageHandler::ReportMessage(isolate, &location, message);
     395             :   }
     396             : 
     397             :   Handle<String> exports_name =
     398        6233 :       isolate->factory()->InternalizeUtf8String("exports");
     399        6233 :   return Object::GetProperty(module_object, exports_name);
     400             : }
     401             : 
     402             : }  // namespace internal
     403             : }  // namespace v8

Generated by: LCOV version 1.10