conversions-inl.h revision f2e3994fa5148cc3d9946666f0b0596290192b0e
1// Copyright 2011 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#ifndef V8_CONVERSIONS_INL_H_
6#define V8_CONVERSIONS_INL_H_
7
8#include <float.h>         // Required for DBL_MAX and on Win32 for finite()
9#include <limits.h>        // Required for INT_MAX etc.
10#include <stdarg.h>
11#include <cmath>
12#include "src/globals.h"       // Required for V8_INFINITY
13#include "src/unicode-cache-inl.h"
14
15// ----------------------------------------------------------------------------
16// Extra POSIX/ANSI functions for Win32/MSVC.
17
18#include "src/base/bits.h"
19#include "src/base/platform/platform.h"
20#include "src/conversions.h"
21#include "src/double.h"
22#include "src/objects-inl.h"
23#include "src/strtod.h"
24
25namespace v8 {
26namespace internal {
27
28inline double JunkStringValue() {
29  return bit_cast<double, uint64_t>(kQuietNaNMask);
30}
31
32
33inline double SignedZero(bool negative) {
34  return negative ? uint64_to_double(Double::kSignMask) : 0.0;
35}
36
37
38// The fast double-to-unsigned-int conversion routine does not guarantee
39// rounding towards zero, or any reasonable value if the argument is larger
40// than what fits in an unsigned 32-bit integer.
41inline unsigned int FastD2UI(double x) {
42  // There is no unsigned version of lrint, so there is no fast path
43  // in this function as there is in FastD2I. Using lrint doesn't work
44  // for values of 2^31 and above.
45
46  // Convert "small enough" doubles to uint32_t by fixing the 32
47  // least significant non-fractional bits in the low 32 bits of the
48  // double, and reading them from there.
49  const double k2Pow52 = 4503599627370496.0;
50  bool negative = x < 0;
51  if (negative) {
52    x = -x;
53  }
54  if (x < k2Pow52) {
55    x += k2Pow52;
56    uint32_t result;
57#ifndef V8_TARGET_BIG_ENDIAN
58    Address mantissa_ptr = reinterpret_cast<Address>(&x);
59#else
60    Address mantissa_ptr = reinterpret_cast<Address>(&x) + kIntSize;
61#endif
62    // Copy least significant 32 bits of mantissa.
63    memcpy(&result, mantissa_ptr, sizeof(result));
64    return negative ? ~result + 1 : result;
65  }
66  // Large number (outside uint32 range), Infinity or NaN.
67  return 0x80000000u;  // Return integer indefinite.
68}
69
70
71inline float DoubleToFloat32(double x) {
72  // TODO(yangguo): This static_cast is implementation-defined behaviour in C++,
73  // so we may need to do the conversion manually instead to match the spec.
74  volatile float f = static_cast<float>(x);
75  return f;
76}
77
78
79inline double DoubleToInteger(double x) {
80  if (std::isnan(x)) return 0;
81  if (!std::isfinite(x) || x == 0) return x;
82  return (x >= 0) ? std::floor(x) : std::ceil(x);
83}
84
85
86int32_t DoubleToInt32(double x) {
87  int32_t i = FastD2I(x);
88  if (FastI2D(i) == x) return i;
89  Double d(x);
90  int exponent = d.Exponent();
91  if (exponent < 0) {
92    if (exponent <= -Double::kSignificandSize) return 0;
93    return d.Sign() * static_cast<int32_t>(d.Significand() >> -exponent);
94  } else {
95    if (exponent > 31) return 0;
96    return d.Sign() * static_cast<int32_t>(d.Significand() << exponent);
97  }
98}
99
100
101bool IsSmiDouble(double value) {
102  return !IsMinusZero(value) && value >= Smi::kMinValue &&
103         value <= Smi::kMaxValue && value == FastI2D(FastD2I(value));
104}
105
106
107bool IsInt32Double(double value) {
108  return !IsMinusZero(value) && value >= kMinInt && value <= kMaxInt &&
109         value == FastI2D(FastD2I(value));
110}
111
112
113bool IsUint32Double(double value) {
114  return !IsMinusZero(value) && value >= 0 && value <= kMaxUInt32 &&
115         value == FastUI2D(FastD2UI(value));
116}
117
118
119int32_t NumberToInt32(Object* number) {
120  if (number->IsSmi()) return Smi::cast(number)->value();
121  return DoubleToInt32(number->Number());
122}
123
124
125uint32_t NumberToUint32(Object* number) {
126  if (number->IsSmi()) return Smi::cast(number)->value();
127  return DoubleToUint32(number->Number());
128}
129
130
131bool TryNumberToSize(Isolate* isolate, Object* number, size_t* result) {
132  SealHandleScope shs(isolate);
133  if (number->IsSmi()) {
134    int value = Smi::cast(number)->value();
135    DCHECK(static_cast<unsigned>(Smi::kMaxValue) <=
136           std::numeric_limits<size_t>::max());
137    if (value >= 0) {
138      *result = static_cast<size_t>(value);
139      return true;
140    }
141    return false;
142  } else {
143    DCHECK(number->IsHeapNumber());
144    double value = HeapNumber::cast(number)->value();
145    if (value >= 0 && value <= std::numeric_limits<size_t>::max()) {
146      *result = static_cast<size_t>(value);
147      return true;
148    } else {
149      return false;
150    }
151  }
152}
153
154
155size_t NumberToSize(Isolate* isolate, Object* number) {
156  size_t result = 0;
157  bool is_valid = TryNumberToSize(isolate, number, &result);
158  CHECK(is_valid);
159  return result;
160}
161
162
163uint32_t DoubleToUint32(double x) {
164  return static_cast<uint32_t>(DoubleToInt32(x));
165}
166
167
168template <class Iterator, class EndMark>
169bool SubStringEquals(Iterator* current,
170                     EndMark end,
171                     const char* substring) {
172  DCHECK(**current == *substring);
173  for (substring++; *substring != '\0'; substring++) {
174    ++*current;
175    if (*current == end || **current != *substring) return false;
176  }
177  ++*current;
178  return true;
179}
180
181
182// Returns true if a nonspace character has been found and false if the
183// end was been reached before finding a nonspace character.
184template <class Iterator, class EndMark>
185inline bool AdvanceToNonspace(UnicodeCache* unicode_cache,
186                              Iterator* current,
187                              EndMark end) {
188  while (*current != end) {
189    if (!unicode_cache->IsWhiteSpaceOrLineTerminator(**current)) return true;
190    ++*current;
191  }
192  return false;
193}
194
195
196// Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end.
197template <int radix_log_2, class Iterator, class EndMark>
198double InternalStringToIntDouble(UnicodeCache* unicode_cache,
199                                 Iterator current,
200                                 EndMark end,
201                                 bool negative,
202                                 bool allow_trailing_junk) {
203  DCHECK(current != end);
204
205  // Skip leading 0s.
206  while (*current == '0') {
207    ++current;
208    if (current == end) return SignedZero(negative);
209  }
210
211  int64_t number = 0;
212  int exponent = 0;
213  const int radix = (1 << radix_log_2);
214
215  do {
216    int digit;
217    if (*current >= '0' && *current <= '9' && *current < '0' + radix) {
218      digit = static_cast<char>(*current) - '0';
219    } else if (radix > 10 && *current >= 'a' && *current < 'a' + radix - 10) {
220      digit = static_cast<char>(*current) - 'a' + 10;
221    } else if (radix > 10 && *current >= 'A' && *current < 'A' + radix - 10) {
222      digit = static_cast<char>(*current) - 'A' + 10;
223    } else {
224      if (allow_trailing_junk ||
225          !AdvanceToNonspace(unicode_cache, &current, end)) {
226        break;
227      } else {
228        return JunkStringValue();
229      }
230    }
231
232    number = number * radix + digit;
233    int overflow = static_cast<int>(number >> 53);
234    if (overflow != 0) {
235      // Overflow occurred. Need to determine which direction to round the
236      // result.
237      int overflow_bits_count = 1;
238      while (overflow > 1) {
239        overflow_bits_count++;
240        overflow >>= 1;
241      }
242
243      int dropped_bits_mask = ((1 << overflow_bits_count) - 1);
244      int dropped_bits = static_cast<int>(number) & dropped_bits_mask;
245      number >>= overflow_bits_count;
246      exponent = overflow_bits_count;
247
248      bool zero_tail = true;
249      while (true) {
250        ++current;
251        if (current == end || !isDigit(*current, radix)) break;
252        zero_tail = zero_tail && *current == '0';
253        exponent += radix_log_2;
254      }
255
256      if (!allow_trailing_junk &&
257          AdvanceToNonspace(unicode_cache, &current, end)) {
258        return JunkStringValue();
259      }
260
261      int middle_value = (1 << (overflow_bits_count - 1));
262      if (dropped_bits > middle_value) {
263        number++;  // Rounding up.
264      } else if (dropped_bits == middle_value) {
265        // Rounding to even to consistency with decimals: half-way case rounds
266        // up if significant part is odd and down otherwise.
267        if ((number & 1) != 0 || !zero_tail) {
268          number++;  // Rounding up.
269        }
270      }
271
272      // Rounding up may cause overflow.
273      if ((number & (static_cast<int64_t>(1) << 53)) != 0) {
274        exponent++;
275        number >>= 1;
276      }
277      break;
278    }
279    ++current;
280  } while (current != end);
281
282  DCHECK(number < ((int64_t)1 << 53));
283  DCHECK(static_cast<int64_t>(static_cast<double>(number)) == number);
284
285  if (exponent == 0) {
286    if (negative) {
287      if (number == 0) return -0.0;
288      number = -number;
289    }
290    return static_cast<double>(number);
291  }
292
293  DCHECK(number != 0);
294  return std::ldexp(static_cast<double>(negative ? -number : number), exponent);
295}
296
297// ES6 18.2.5 parseInt(string, radix)
298template <class Iterator, class EndMark>
299double InternalStringToInt(UnicodeCache* unicode_cache,
300                           Iterator current,
301                           EndMark end,
302                           int radix) {
303  const bool allow_trailing_junk = true;
304  const double empty_string_val = JunkStringValue();
305
306  if (!AdvanceToNonspace(unicode_cache, &current, end)) {
307    return empty_string_val;
308  }
309
310  bool negative = false;
311  bool leading_zero = false;
312
313  if (*current == '+') {
314    // Ignore leading sign; skip following spaces.
315    ++current;
316    if (current == end) {
317      return JunkStringValue();
318    }
319  } else if (*current == '-') {
320    ++current;
321    if (current == end) {
322      return JunkStringValue();
323    }
324    negative = true;
325  }
326
327  if (radix == 0) {
328    // Radix detection.
329    radix = 10;
330    if (*current == '0') {
331      ++current;
332      if (current == end) return SignedZero(negative);
333      if (*current == 'x' || *current == 'X') {
334        radix = 16;
335        ++current;
336        if (current == end) return JunkStringValue();
337      } else {
338        leading_zero = true;
339      }
340    }
341  } else if (radix == 16) {
342    if (*current == '0') {
343      // Allow "0x" prefix.
344      ++current;
345      if (current == end) return SignedZero(negative);
346      if (*current == 'x' || *current == 'X') {
347        ++current;
348        if (current == end) return JunkStringValue();
349      } else {
350        leading_zero = true;
351      }
352    }
353  }
354
355  if (radix < 2 || radix > 36) return JunkStringValue();
356
357  // Skip leading zeros.
358  while (*current == '0') {
359    leading_zero = true;
360    ++current;
361    if (current == end) return SignedZero(negative);
362  }
363
364  if (!leading_zero && !isDigit(*current, radix)) {
365    return JunkStringValue();
366  }
367
368  if (base::bits::IsPowerOfTwo32(radix)) {
369    switch (radix) {
370      case 2:
371        return InternalStringToIntDouble<1>(
372            unicode_cache, current, end, negative, allow_trailing_junk);
373      case 4:
374        return InternalStringToIntDouble<2>(
375            unicode_cache, current, end, negative, allow_trailing_junk);
376      case 8:
377        return InternalStringToIntDouble<3>(
378            unicode_cache, current, end, negative, allow_trailing_junk);
379
380      case 16:
381        return InternalStringToIntDouble<4>(
382            unicode_cache, current, end, negative, allow_trailing_junk);
383
384      case 32:
385        return InternalStringToIntDouble<5>(
386            unicode_cache, current, end, negative, allow_trailing_junk);
387      default:
388        UNREACHABLE();
389    }
390  }
391
392  if (radix == 10) {
393    // Parsing with strtod.
394    const int kMaxSignificantDigits = 309;  // Doubles are less than 1.8e308.
395    // The buffer may contain up to kMaxSignificantDigits + 1 digits and a zero
396    // end.
397    const int kBufferSize = kMaxSignificantDigits + 2;
398    char buffer[kBufferSize];
399    int buffer_pos = 0;
400    while (*current >= '0' && *current <= '9') {
401      if (buffer_pos <= kMaxSignificantDigits) {
402        // If the number has more than kMaxSignificantDigits it will be parsed
403        // as infinity.
404        DCHECK(buffer_pos < kBufferSize);
405        buffer[buffer_pos++] = static_cast<char>(*current);
406      }
407      ++current;
408      if (current == end) break;
409    }
410
411    if (!allow_trailing_junk &&
412        AdvanceToNonspace(unicode_cache, &current, end)) {
413      return JunkStringValue();
414    }
415
416    SLOW_DCHECK(buffer_pos < kBufferSize);
417    buffer[buffer_pos] = '\0';
418    Vector<const char> buffer_vector(buffer, buffer_pos);
419    return negative ? -Strtod(buffer_vector, 0) : Strtod(buffer_vector, 0);
420  }
421
422  // The following code causes accumulating rounding error for numbers greater
423  // than ~2^56. It's explicitly allowed in the spec: "if R is not 2, 4, 8, 10,
424  // 16, or 32, then mathInt may be an implementation-dependent approximation to
425  // the mathematical integer value" (15.1.2.2).
426
427  int lim_0 = '0' + (radix < 10 ? radix : 10);
428  int lim_a = 'a' + (radix - 10);
429  int lim_A = 'A' + (radix - 10);
430
431  // NOTE: The code for computing the value may seem a bit complex at
432  // first glance. It is structured to use 32-bit multiply-and-add
433  // loops as long as possible to avoid loosing precision.
434
435  double v = 0.0;
436  bool done = false;
437  do {
438    // Parse the longest part of the string starting at index j
439    // possible while keeping the multiplier, and thus the part
440    // itself, within 32 bits.
441    unsigned int part = 0, multiplier = 1;
442    while (true) {
443      int d;
444      if (*current >= '0' && *current < lim_0) {
445        d = *current - '0';
446      } else if (*current >= 'a' && *current < lim_a) {
447        d = *current - 'a' + 10;
448      } else if (*current >= 'A' && *current < lim_A) {
449        d = *current - 'A' + 10;
450      } else {
451        done = true;
452        break;
453      }
454
455      // Update the value of the part as long as the multiplier fits
456      // in 32 bits. When we can't guarantee that the next iteration
457      // will not overflow the multiplier, we stop parsing the part
458      // by leaving the loop.
459      const unsigned int kMaximumMultiplier = 0xffffffffU / 36;
460      uint32_t m = multiplier * radix;
461      if (m > kMaximumMultiplier) break;
462      part = part * radix + d;
463      multiplier = m;
464      DCHECK(multiplier > part);
465
466      ++current;
467      if (current == end) {
468        done = true;
469        break;
470      }
471    }
472
473    // Update the value and skip the part in the string.
474    v = v * multiplier + part;
475  } while (!done);
476
477  if (!allow_trailing_junk &&
478      AdvanceToNonspace(unicode_cache, &current, end)) {
479    return JunkStringValue();
480  }
481
482  return negative ? -v : v;
483}
484
485
486// Converts a string to a double value. Assumes the Iterator supports
487// the following operations:
488// 1. current == end (other ops are not allowed), current != end.
489// 2. *current - gets the current character in the sequence.
490// 3. ++current (advances the position).
491template <class Iterator, class EndMark>
492double InternalStringToDouble(UnicodeCache* unicode_cache,
493                              Iterator current,
494                              EndMark end,
495                              int flags,
496                              double empty_string_val) {
497  // To make sure that iterator dereferencing is valid the following
498  // convention is used:
499  // 1. Each '++current' statement is followed by check for equality to 'end'.
500  // 2. If AdvanceToNonspace returned false then current == end.
501  // 3. If 'current' becomes be equal to 'end' the function returns or goes to
502  // 'parsing_done'.
503  // 4. 'current' is not dereferenced after the 'parsing_done' label.
504  // 5. Code before 'parsing_done' may rely on 'current != end'.
505  if (!AdvanceToNonspace(unicode_cache, &current, end)) {
506    return empty_string_val;
507  }
508
509  const bool allow_trailing_junk = (flags & ALLOW_TRAILING_JUNK) != 0;
510
511  // The longest form of simplified number is: "-<significant digits>'.1eXXX\0".
512  const int kBufferSize = kMaxSignificantDigits + 10;
513  char buffer[kBufferSize];  // NOLINT: size is known at compile time.
514  int buffer_pos = 0;
515
516  // Exponent will be adjusted if insignificant digits of the integer part
517  // or insignificant leading zeros of the fractional part are dropped.
518  int exponent = 0;
519  int significant_digits = 0;
520  int insignificant_digits = 0;
521  bool nonzero_digit_dropped = false;
522
523  enum Sign {
524    NONE,
525    NEGATIVE,
526    POSITIVE
527  };
528
529  Sign sign = NONE;
530
531  if (*current == '+') {
532    // Ignore leading sign.
533    ++current;
534    if (current == end) return JunkStringValue();
535    sign = POSITIVE;
536  } else if (*current == '-') {
537    ++current;
538    if (current == end) return JunkStringValue();
539    sign = NEGATIVE;
540  }
541
542  static const char kInfinityString[] = "Infinity";
543  if (*current == kInfinityString[0]) {
544    if (!SubStringEquals(&current, end, kInfinityString)) {
545      return JunkStringValue();
546    }
547
548    if (!allow_trailing_junk &&
549        AdvanceToNonspace(unicode_cache, &current, end)) {
550      return JunkStringValue();
551    }
552
553    DCHECK(buffer_pos == 0);
554    return (sign == NEGATIVE) ? -V8_INFINITY : V8_INFINITY;
555  }
556
557  bool leading_zero = false;
558  if (*current == '0') {
559    ++current;
560    if (current == end) return SignedZero(sign == NEGATIVE);
561
562    leading_zero = true;
563
564    // It could be hexadecimal value.
565    if ((flags & ALLOW_HEX) && (*current == 'x' || *current == 'X')) {
566      ++current;
567      if (current == end || !isDigit(*current, 16) || sign != NONE) {
568        return JunkStringValue();  // "0x".
569      }
570
571      return InternalStringToIntDouble<4>(unicode_cache,
572                                          current,
573                                          end,
574                                          false,
575                                          allow_trailing_junk);
576
577    // It could be an explicit octal value.
578    } else if ((flags & ALLOW_OCTAL) && (*current == 'o' || *current == 'O')) {
579      ++current;
580      if (current == end || !isDigit(*current, 8) || sign != NONE) {
581        return JunkStringValue();  // "0o".
582      }
583
584      return InternalStringToIntDouble<3>(unicode_cache,
585                                          current,
586                                          end,
587                                          false,
588                                          allow_trailing_junk);
589
590    // It could be a binary value.
591    } else if ((flags & ALLOW_BINARY) && (*current == 'b' || *current == 'B')) {
592      ++current;
593      if (current == end || !isBinaryDigit(*current) || sign != NONE) {
594        return JunkStringValue();  // "0b".
595      }
596
597      return InternalStringToIntDouble<1>(unicode_cache,
598                                          current,
599                                          end,
600                                          false,
601                                          allow_trailing_junk);
602    }
603
604    // Ignore leading zeros in the integer part.
605    while (*current == '0') {
606      ++current;
607      if (current == end) return SignedZero(sign == NEGATIVE);
608    }
609  }
610
611  bool octal = leading_zero && (flags & ALLOW_IMPLICIT_OCTAL) != 0;
612
613  // Copy significant digits of the integer part (if any) to the buffer.
614  while (*current >= '0' && *current <= '9') {
615    if (significant_digits < kMaxSignificantDigits) {
616      DCHECK(buffer_pos < kBufferSize);
617      buffer[buffer_pos++] = static_cast<char>(*current);
618      significant_digits++;
619      // Will later check if it's an octal in the buffer.
620    } else {
621      insignificant_digits++;  // Move the digit into the exponential part.
622      nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
623    }
624    octal = octal && *current < '8';
625    ++current;
626    if (current == end) goto parsing_done;
627  }
628
629  if (significant_digits == 0) {
630    octal = false;
631  }
632
633  if (*current == '.') {
634    if (octal && !allow_trailing_junk) return JunkStringValue();
635    if (octal) goto parsing_done;
636
637    ++current;
638    if (current == end) {
639      if (significant_digits == 0 && !leading_zero) {
640        return JunkStringValue();
641      } else {
642        goto parsing_done;
643      }
644    }
645
646    if (significant_digits == 0) {
647      // octal = false;
648      // Integer part consists of 0 or is absent. Significant digits start after
649      // leading zeros (if any).
650      while (*current == '0') {
651        ++current;
652        if (current == end) return SignedZero(sign == NEGATIVE);
653        exponent--;  // Move this 0 into the exponent.
654      }
655    }
656
657    // There is a fractional part.  We don't emit a '.', but adjust the exponent
658    // instead.
659    while (*current >= '0' && *current <= '9') {
660      if (significant_digits < kMaxSignificantDigits) {
661        DCHECK(buffer_pos < kBufferSize);
662        buffer[buffer_pos++] = static_cast<char>(*current);
663        significant_digits++;
664        exponent--;
665      } else {
666        // Ignore insignificant digits in the fractional part.
667        nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
668      }
669      ++current;
670      if (current == end) goto parsing_done;
671    }
672  }
673
674  if (!leading_zero && exponent == 0 && significant_digits == 0) {
675    // If leading_zeros is true then the string contains zeros.
676    // If exponent < 0 then string was [+-]\.0*...
677    // If significant_digits != 0 the string is not equal to 0.
678    // Otherwise there are no digits in the string.
679    return JunkStringValue();
680  }
681
682  // Parse exponential part.
683  if (*current == 'e' || *current == 'E') {
684    if (octal) return JunkStringValue();
685    ++current;
686    if (current == end) {
687      if (allow_trailing_junk) {
688        goto parsing_done;
689      } else {
690        return JunkStringValue();
691      }
692    }
693    char sign = '+';
694    if (*current == '+' || *current == '-') {
695      sign = static_cast<char>(*current);
696      ++current;
697      if (current == end) {
698        if (allow_trailing_junk) {
699          goto parsing_done;
700        } else {
701          return JunkStringValue();
702        }
703      }
704    }
705
706    if (current == end || *current < '0' || *current > '9') {
707      if (allow_trailing_junk) {
708        goto parsing_done;
709      } else {
710        return JunkStringValue();
711      }
712    }
713
714    const int max_exponent = INT_MAX / 2;
715    DCHECK(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2);
716    int num = 0;
717    do {
718      // Check overflow.
719      int digit = *current - '0';
720      if (num >= max_exponent / 10
721          && !(num == max_exponent / 10 && digit <= max_exponent % 10)) {
722        num = max_exponent;
723      } else {
724        num = num * 10 + digit;
725      }
726      ++current;
727    } while (current != end && *current >= '0' && *current <= '9');
728
729    exponent += (sign == '-' ? -num : num);
730  }
731
732  if (!allow_trailing_junk &&
733      AdvanceToNonspace(unicode_cache, &current, end)) {
734    return JunkStringValue();
735  }
736
737  parsing_done:
738  exponent += insignificant_digits;
739
740  if (octal) {
741    return InternalStringToIntDouble<3>(unicode_cache,
742                                        buffer,
743                                        buffer + buffer_pos,
744                                        sign == NEGATIVE,
745                                        allow_trailing_junk);
746  }
747
748  if (nonzero_digit_dropped) {
749    buffer[buffer_pos++] = '1';
750    exponent--;
751  }
752
753  SLOW_DCHECK(buffer_pos < kBufferSize);
754  buffer[buffer_pos] = '\0';
755
756  double converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
757  return (sign == NEGATIVE) ? -converted : converted;
758}
759
760}  // namespace internal
761}  // namespace v8
762
763#endif  // V8_CONVERSIONS_INL_H_
764