blob: 3c65d09d2b1dcd06747c54222d65e6e46ef98f41 [file] [log] [blame]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000043#include "date.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000045#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000046#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000048#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000049#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000050#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000051#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000052#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000054#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000055#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000057#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000058#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000059#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000060#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000061#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062
kasperl@chromium.org71affb52009-05-26 05:44:31 +000063namespace v8 {
64namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
66
ager@chromium.org3e875802009-06-29 08:26:34 +000067#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000068 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000069
70// Cast the given object to a value of the specified type and store
71// it in a variable with the given name. If the object is not of the
72// expected type call IllegalOperation and return.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073#define CONVERT_ARG_CHECKED(Type, name, index) \
74 RUNTIME_ASSERT(args[index]->Is##Type()); \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000075 Type* name = Type::cast(args[index]);
76
77#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
78 RUNTIME_ASSERT(args[index]->Is##Type()); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000079 Handle<Type> name = args.at<Type>(index);
80
kasper.lundbd3ec4e2008-07-09 11:06:54 +000081// Cast the given object to a boolean and store it in a variable with
82// the given name. If the object is not a boolean call IllegalOperation
83// and return.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000084#define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
85 RUNTIME_ASSERT(args[index]->IsBoolean()); \
86 bool name = args[index]->IsTrue();
kasper.lundbd3ec4e2008-07-09 11:06:54 +000087
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000088// Cast the given argument to a Smi and store its value in an int variable
89// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000090// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000091#define CONVERT_SMI_ARG_CHECKED(name, index) \
92 RUNTIME_ASSERT(args[index]->IsSmi()); \
93 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000094
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000095// Cast the given argument to a double and store it in a variable with
96// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000098#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
99 RUNTIME_ASSERT(args[index]->IsNumber()); \
100 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101
102// Call the specified converter on the object *comand store the result in
103// a variable of the specified type with the given name. If the
104// object is not a Number call IllegalOperation and return.
105#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
106 RUNTIME_ASSERT(obj->IsNumber()); \
107 type name = NumberTo##Type(obj);
108
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000110// Cast the given argument to PropertyDetails and store its value in a
111// variable with the given name. If the argument is not a Smi call
112// IllegalOperation and return.
113#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
114 RUNTIME_ASSERT(args[index]->IsSmi()); \
115 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
116
117
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000118// Assert that the given argument has a valid value for a StrictModeFlag
119// and store it in a StrictModeFlag variable with the given name.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000120#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
121 RUNTIME_ASSERT(args[index]->IsSmi()); \
122 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
123 args.smi_at(index) == kNonStrictMode); \
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000124 StrictModeFlag name = \
125 static_cast<StrictModeFlag>(args.smi_at(index));
126
127
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000128// Assert that the given argument has a valid value for a LanguageMode
129// and store it in a LanguageMode variable with the given name.
130#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
131 ASSERT(args[index]->IsSmi()); \
132 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
133 args.smi_at(index) == STRICT_MODE || \
134 args.smi_at(index) == EXTENDED_MODE); \
135 LanguageMode name = \
136 static_cast<LanguageMode>(args.smi_at(index));
137
138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000139MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
140 JSObject* boilerplate) {
141 StackLimitCheck check(isolate);
142 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000143
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000144 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000146 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000147 if (!maybe_result->ToObject(&result)) return maybe_result;
148 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 JSObject* copy = JSObject::cast(result);
150
151 // Deep copy local properties.
152 if (copy->HasFastProperties()) {
153 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 for (int i = 0; i < properties->length(); i++) {
155 Object* value = properties->get(i);
156 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000157 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000158 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 if (!maybe_result->ToObject(&result)) return maybe_result;
160 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000161 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000162 }
163 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000164 int nof = copy->map()->inobject_properties();
165 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000166 Object* value = copy->InObjectPropertyAt(i);
167 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000168 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000169 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000170 if (!maybe_result->ToObject(&result)) return maybe_result;
171 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000172 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000173 }
174 }
175 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000176 { MaybeObject* maybe_result =
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000177 heap->AllocateFixedArray(copy->NumberOfLocalProperties());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000178 if (!maybe_result->ToObject(&result)) return maybe_result;
179 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000180 FixedArray* names = FixedArray::cast(result);
181 copy->GetLocalPropertyNames(names, 0);
182 for (int i = 0; i < names->length(); i++) {
183 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000184 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000185 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000186 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000187 // Only deep copy fields from the object literal expression.
188 // In particular, don't try to copy the length attribute of
189 // an array.
190 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000191 Object* value =
192 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000194 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000195 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000196 if (!maybe_result->ToObject(&result)) return maybe_result;
197 }
198 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000199 // Creating object copy for literals. No strict mode needed.
200 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000201 if (!maybe_result->ToObject(&result)) return maybe_result;
202 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000203 }
204 }
205 }
206
207 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000208 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000209 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000210 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000211 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000212 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000213 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000214 if (elements->map() == heap->fixed_cow_array_map()) {
215 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000216#ifdef DEBUG
217 for (int i = 0; i < elements->length(); i++) {
218 ASSERT(!elements->get(i)->IsJSObject());
219 }
220#endif
221 } else {
222 for (int i = 0; i < elements->length(); i++) {
223 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000224 ASSERT(value->IsSmi() ||
225 value->IsTheHole() ||
226 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000227 if (value->IsJSObject()) {
228 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
230 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000231 if (!maybe_result->ToObject(&result)) return maybe_result;
232 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000233 elements->set(i, result);
234 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000235 }
236 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000237 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000238 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000239 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000240 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000241 int capacity = element_dictionary->Capacity();
242 for (int i = 0; i < capacity; i++) {
243 Object* k = element_dictionary->KeyAt(i);
244 if (element_dictionary->IsKey(k)) {
245 Object* value = element_dictionary->ValueAt(i);
246 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000247 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000248 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
249 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000250 if (!maybe_result->ToObject(&result)) return maybe_result;
251 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000252 element_dictionary->ValueAtPut(i, result);
253 }
254 }
255 }
256 break;
257 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000258 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000259 UNIMPLEMENTED();
260 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000261 case EXTERNAL_PIXEL_ELEMENTS:
262 case EXTERNAL_BYTE_ELEMENTS:
263 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
264 case EXTERNAL_SHORT_ELEMENTS:
265 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
266 case EXTERNAL_INT_ELEMENTS:
267 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
268 case EXTERNAL_FLOAT_ELEMENTS:
269 case EXTERNAL_DOUBLE_ELEMENTS:
270 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000271 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000272 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000273 }
274 return copy;
275}
276
277
ager@chromium.org236ad962008-09-25 09:45:57 +0000278static Handle<Map> ComputeObjectLiteralMap(
279 Handle<Context> context,
280 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000281 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000282 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000283 int properties_length = constant_properties->length();
284 int number_of_properties = properties_length / 2;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000285 // Check that there are only symbols and array indices among keys.
286 int number_of_symbol_keys = 0;
287 for (int p = 0; p != properties_length; p += 2) {
288 Object* key = constant_properties->get(p);
289 uint32_t element_index = 0;
290 if (key->IsSymbol()) {
291 number_of_symbol_keys++;
292 } else if (key->ToArrayIndex(&element_index)) {
293 // An index key does not require space in the property backing store.
294 number_of_properties--;
295 } else {
296 // Bail out as a non-symbol non-index key makes caching impossible.
297 // ASSERT to make sure that the if condition after the loop is false.
298 ASSERT(number_of_symbol_keys != number_of_properties);
299 break;
ager@chromium.org236ad962008-09-25 09:45:57 +0000300 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000301 }
302 // If we only have symbols and array indices among keys then we can
303 // use the map cache in the global context.
304 const int kMaxKeys = 10;
305 if ((number_of_symbol_keys == number_of_properties) &&
306 (number_of_symbol_keys < kMaxKeys)) {
307 // Create the fixed array with the key.
308 Handle<FixedArray> keys =
309 isolate->factory()->NewFixedArray(number_of_symbol_keys);
310 if (number_of_symbol_keys > 0) {
311 int index = 0;
312 for (int p = 0; p < properties_length; p += 2) {
313 Object* key = constant_properties->get(p);
314 if (key->IsSymbol()) {
315 keys->set(index++, key);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000316 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000317 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000318 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000319 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000320 *is_result_from_cache = true;
321 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000322 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000323 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000325 Handle<Map>(context->object_function()->initial_map()),
326 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000327}
328
329
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000330static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000332 Handle<FixedArray> literals,
333 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000334
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000335
336static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000337 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000338 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000339 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000340 bool should_have_fast_elements,
341 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000342 // Get the global context from the literals array. This is the
343 // context in which the function was created and we use the object
344 // function from this context to create the object literal. We do
345 // not use the object function from the current global context
346 // because this might be the object function from another context
347 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000348 Handle<Context> context =
349 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000351 // In case we have function literals, we want the object to be in
352 // slow properties mode for now. We don't go in the map cache because
353 // maps with constant functions can't be shared if the functions are
354 // not the same (which is the common case).
355 bool is_result_from_cache = false;
356 Handle<Map> map = has_function_literal
357 ? Handle<Map>(context->object_function()->initial_map())
358 : ComputeObjectLiteralMap(context,
359 constant_properties,
360 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000362 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000363
364 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000365 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000366
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000367 // Add the constant properties to the boilerplate.
368 int length = constant_properties->length();
369 bool should_transform =
370 !is_result_from_cache && boilerplate->HasFastProperties();
371 if (should_transform || has_function_literal) {
372 // Normalize the properties of object to avoid n^2 behavior
373 // when extending the object multiple properties. Indicate the number of
374 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000375 JSObject::NormalizeProperties(
376 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000377 }
378
379 for (int index = 0; index < length; index +=2) {
380 Handle<Object> key(constant_properties->get(index+0), isolate);
381 Handle<Object> value(constant_properties->get(index+1), isolate);
382 if (value->IsFixedArray()) {
383 // The value contains the constant_properties of a
384 // simple object or array literal.
385 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
386 value = CreateLiteralBoilerplate(isolate, literals, array);
387 if (value.is_null()) return value;
388 }
389 Handle<Object> result;
390 uint32_t element_index = 0;
391 if (key->IsSymbol()) {
392 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
393 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000394 result = JSObject::SetOwnElement(
395 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 Handle<String> name(String::cast(*key));
398 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000399 result = JSObject::SetLocalPropertyIgnoreAttributes(
400 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000402 } else if (key->ToArrayIndex(&element_index)) {
403 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000404 result = JSObject::SetOwnElement(
405 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000406 } else {
407 // Non-uint32 number.
408 ASSERT(key->IsNumber());
409 double num = key->Number();
410 char arr[100];
411 Vector<char> buffer(arr, ARRAY_SIZE(arr));
412 const char* str = DoubleToCString(num, buffer);
413 Handle<String> name =
414 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000415 result = JSObject::SetLocalPropertyIgnoreAttributes(
416 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 // If setting the property on the boilerplate throws an
419 // exception, the exception is converted to an empty handle in
420 // the handle based operations. In that case, we need to
421 // convert back to an exception.
422 if (result.is_null()) return result;
423 }
424
425 // Transform to fast properties if necessary. For object literals with
426 // containing function literals we defer this operation until after all
427 // computed properties have been assigned so that we can generate
428 // constant function properties.
429 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000430 JSObject::TransformToFastProperties(
431 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432 }
433
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000434 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000435}
436
437
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000438MaybeObject* TransitionElements(Handle<Object> object,
439 ElementsKind to_kind,
440 Isolate* isolate) {
441 HandleScope scope(isolate);
442 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
443 ElementsKind from_kind =
444 Handle<JSObject>::cast(object)->map()->elements_kind();
445 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
446 Handle<Object> result = JSObject::TransitionElementsKind(
447 Handle<JSObject>::cast(object), to_kind);
448 if (result.is_null()) return isolate->ThrowIllegalOperation();
449 return *result;
450 }
451 return isolate->ThrowIllegalOperation();
452}
453
454
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000455static const int kSmiOnlyLiteralMinimumLength = 1024;
456
457
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000458Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000459 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000460 Handle<FixedArray> literals,
461 Handle<FixedArray> elements) {
462 // Create the JSArray.
463 Handle<JSFunction> constructor(
464 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000465 Handle<JSArray> object =
466 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000468 ElementsKind constant_elements_kind =
469 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
470 Handle<FixedArrayBase> constant_elements_values(
471 FixedArrayBase::cast(elements->get(1)));
472
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000473 Context* global_context = isolate->context()->global_context();
474 if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
475 object->set_map(Map::cast(global_context->smi_js_array_map()));
476 } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
477 object->set_map(Map::cast(global_context->double_js_array_map()));
478 } else {
479 object->set_map(Map::cast(global_context->object_js_array_map()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000482 Handle<FixedArrayBase> copied_elements_values;
483 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
484 ASSERT(FLAG_smi_only_arrays);
485 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
486 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000487 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000488 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
489 constant_elements_kind == FAST_ELEMENTS);
490 const bool is_cow =
491 (constant_elements_values->map() ==
492 isolate->heap()->fixed_cow_array_map());
493 if (is_cow) {
494 copied_elements_values = constant_elements_values;
495#if DEBUG
496 Handle<FixedArray> fixed_array_values =
497 Handle<FixedArray>::cast(copied_elements_values);
498 for (int i = 0; i < fixed_array_values->length(); i++) {
499 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
500 }
501#endif
502 } else {
503 Handle<FixedArray> fixed_array_values =
504 Handle<FixedArray>::cast(constant_elements_values);
505 Handle<FixedArray> fixed_array_values_copy =
506 isolate->factory()->CopyFixedArray(fixed_array_values);
507 copied_elements_values = fixed_array_values_copy;
508 for (int i = 0; i < fixed_array_values->length(); i++) {
509 Object* current = fixed_array_values->get(i);
510 if (current->IsFixedArray()) {
511 // The value contains the constant_properties of a
512 // simple object or array literal.
513 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
514 Handle<Object> result =
515 CreateLiteralBoilerplate(isolate, literals, fa);
516 if (result.is_null()) return result;
517 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000518 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000519 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000520 }
521 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000522 object->set_elements(*copied_elements_values);
523 object->set_length(Smi::FromInt(copied_elements_values->length()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000524
525 // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
526 // on or the object is larger than the threshold.
527 if (!FLAG_smi_only_arrays &&
528 constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
529 if (object->GetElementsKind() != FAST_ELEMENTS) {
530 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
531 }
532 }
533
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000534 return object;
535}
536
537
538static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000540 Handle<FixedArray> literals,
541 Handle<FixedArray> array) {
542 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000543 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000544 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000545 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 return CreateObjectLiteralBoilerplate(isolate,
547 literals,
548 elements,
549 true,
550 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000551 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000552 return CreateObjectLiteralBoilerplate(isolate,
553 literals,
554 elements,
555 false,
556 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000557 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000558 return Runtime::CreateArrayLiteralBoilerplate(
559 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000560 default:
561 UNREACHABLE();
562 return Handle<Object>::null();
563 }
564}
565
566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000567RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000569 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000570 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000571 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000572 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000573 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000574 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
575 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576
577 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 Handle<Object> boilerplate(literals->get(literals_index), isolate);
579 if (*boilerplate == isolate->heap()->undefined_value()) {
580 boilerplate = CreateObjectLiteralBoilerplate(isolate,
581 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000582 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 should_have_fast_elements,
584 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000585 if (boilerplate.is_null()) return Failure::Exception();
586 // Update the functions literal and return the boilerplate.
587 literals->set(literals_index, *boilerplate);
588 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000589 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000590}
591
592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000593RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000594 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000595 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000596 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000597 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000598 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000599 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
601 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602
603 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000604 Handle<Object> boilerplate(literals->get(literals_index), isolate);
605 if (*boilerplate == isolate->heap()->undefined_value()) {
606 boilerplate = CreateObjectLiteralBoilerplate(isolate,
607 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000608 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000609 should_have_fast_elements,
610 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000611 if (boilerplate.is_null()) return Failure::Exception();
612 // Update the functions literal and return the boilerplate.
613 literals->set(literals_index, *boilerplate);
614 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000615 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000616}
617
618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000619RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000620 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000621 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000622 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000623 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000624 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000625
626 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000627 Handle<Object> boilerplate(literals->get(literals_index), isolate);
628 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000629 boilerplate =
630 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000631 if (boilerplate.is_null()) return Failure::Exception();
632 // Update the functions literal and return the boilerplate.
633 literals->set(literals_index, *boilerplate);
634 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000635 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000636}
637
638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000640 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000641 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000642 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000643 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000644 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000645
646 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 Handle<Object> boilerplate(literals->get(literals_index), isolate);
648 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000649 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000650 boilerplate =
651 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000652 if (boilerplate.is_null()) return Failure::Exception();
653 // Update the functions literal and return the boilerplate.
654 literals->set(literals_index, *boilerplate);
655 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000656 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000657 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000658 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000659 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000660 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000661}
662
663
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
665 ASSERT(args.length() == 2);
666 Object* handler = args[0];
667 Object* prototype = args[1];
668 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000670 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
671}
672
673
lrn@chromium.org34e60782011-09-15 07:25:40 +0000674RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
675 ASSERT(args.length() == 4);
676 Object* handler = args[0];
677 Object* call_trap = args[1];
678 Object* construct_trap = args[2];
679 Object* prototype = args[3];
680 Object* used_prototype =
681 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
682 return isolate->heap()->AllocateJSFunctionProxy(
683 handler, call_trap, construct_trap, used_prototype);
684}
685
686
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000687RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
688 ASSERT(args.length() == 1);
689 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000690 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000691}
692
693
lrn@chromium.org34e60782011-09-15 07:25:40 +0000694RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
695 ASSERT(args.length() == 1);
696 Object* obj = args[0];
697 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
698}
699
700
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000701RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
702 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000703 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000704 return proxy->handler();
705}
706
707
lrn@chromium.org34e60782011-09-15 07:25:40 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
709 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000710 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000711 return proxy->call_trap();
712}
713
714
715RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
716 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000717 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000718 return proxy->construct_trap();
719}
720
721
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000722RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
723 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000724 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000725 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000726 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000727}
728
729
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000733 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000734 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
735 holder->set_table(*table);
736 return *holder;
737}
738
739
740RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
741 HandleScope scope(isolate);
742 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000743 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000744 Handle<Object> key(args[1]);
745 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
746 table = ObjectHashSetAdd(table, key);
747 holder->set_table(*table);
748 return isolate->heap()->undefined_symbol();
749}
750
751
752RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000755 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000756 Handle<Object> key(args[1]);
757 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
758 return isolate->heap()->ToBoolean(table->Contains(*key));
759}
760
761
762RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
763 HandleScope scope(isolate);
764 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000765 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000766 Handle<Object> key(args[1]);
767 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
768 table = ObjectHashSetRemove(table, key);
769 holder->set_table(*table);
770 return isolate->heap()->undefined_symbol();
771}
772
773
774RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
775 HandleScope scope(isolate);
776 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000777 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000778 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
779 holder->set_table(*table);
780 return *holder;
781}
782
783
784RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000787 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000788 Handle<Object> key(args[1]);
789 return ObjectHashTable::cast(holder->table())->Lookup(*key);
790}
791
792
793RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
794 HandleScope scope(isolate);
795 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000796 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000797 Handle<Object> key(args[1]);
798 Handle<Object> value(args[2]);
799 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
800 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
801 holder->set_table(*new_table);
802 return *value;
803}
804
805
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000806RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
807 HandleScope scope(isolate);
808 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000809 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000810 ASSERT(weakmap->map()->inobject_properties() == 0);
811 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
812 weakmap->set_table(*table);
813 weakmap->set_next(Smi::FromInt(0));
814 return *weakmap;
815}
816
817
818RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
819 NoHandleAllocation ha;
820 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000821 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
822 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000823 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000824}
825
826
827RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
828 HandleScope scope(isolate);
829 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000830 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
831 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000832 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000833 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000834 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
835 weakmap->set_table(*new_table);
836 return *value;
837}
838
839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000840RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000841 NoHandleAllocation ha;
842 ASSERT(args.length() == 1);
843 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 return JSObject::cast(obj)->class_name();
846}
847
ager@chromium.org7c537e22008-10-16 08:43:32 +0000848
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000849RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
850 NoHandleAllocation ha;
851 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000852 CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000853 Object* obj = input_obj;
854 // We don't expect access checks to be needed on JSProxy objects.
855 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000856 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000857 if (obj->IsAccessCheckNeeded() &&
858 !isolate->MayNamedAccess(JSObject::cast(obj),
859 isolate->heap()->Proto_symbol(),
860 v8::ACCESS_GET)) {
861 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
862 return isolate->heap()->undefined_value();
863 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000864 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000865 } while (obj->IsJSObject() &&
866 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000867 return obj;
868}
869
870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000871RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000872 NoHandleAllocation ha;
873 ASSERT(args.length() == 2);
874 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
875 Object* O = args[0];
876 Object* V = args[1];
877 while (true) {
878 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000879 if (prototype->IsNull()) return isolate->heap()->false_value();
880 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000881 V = prototype;
882 }
883}
884
885
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000886// Recursively traverses hidden prototypes if property is not found
887static void GetOwnPropertyImplementation(JSObject* obj,
888 String* name,
889 LookupResult* result) {
890 obj->LocalLookupRealNamedProperty(name, result);
891
892 if (!result->IsProperty()) {
893 Object* proto = obj->GetPrototype();
894 if (proto->IsJSObject() &&
895 JSObject::cast(proto)->map()->is_hidden_prototype())
896 GetOwnPropertyImplementation(JSObject::cast(proto),
897 name, result);
898 }
899}
900
901
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000902static bool CheckAccessException(LookupResult* result,
903 v8::AccessType access_type) {
904 if (result->type() == CALLBACKS) {
905 Object* callback = result->GetCallbackObject();
906 if (callback->IsAccessorInfo()) {
907 AccessorInfo* info = AccessorInfo::cast(callback);
908 bool can_access =
909 (access_type == v8::ACCESS_HAS &&
910 (info->all_can_read() || info->all_can_write())) ||
911 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
912 (access_type == v8::ACCESS_SET && info->all_can_write());
913 return can_access;
914 }
915 }
916
917 return false;
918}
919
920
921static bool CheckAccess(JSObject* obj,
922 String* name,
923 LookupResult* result,
924 v8::AccessType access_type) {
925 ASSERT(result->IsProperty());
926
927 JSObject* holder = result->holder();
928 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000929 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000930 while (true) {
931 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000933 // Access check callback denied the access, but some properties
934 // can have a special permissions which override callbacks descision
935 // (currently see v8::AccessControl).
936 break;
937 }
938
939 if (current == holder) {
940 return true;
941 }
942
943 current = JSObject::cast(current->GetPrototype());
944 }
945
946 // API callbacks can have per callback access exceptions.
947 switch (result->type()) {
948 case CALLBACKS: {
949 if (CheckAccessException(result, access_type)) {
950 return true;
951 }
952 break;
953 }
954 case INTERCEPTOR: {
955 // If the object has an interceptor, try real named properties.
956 // Overwrite the result to fetch the correct property later.
957 holder->LookupRealNamedProperty(name, result);
958 if (result->IsProperty()) {
959 if (CheckAccessException(result, access_type)) {
960 return true;
961 }
962 }
963 break;
964 }
965 default:
966 break;
967 }
968
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000970 return false;
971}
972
973
974// TODO(1095): we should traverse hidden prototype hierachy as well.
975static bool CheckElementAccess(JSObject* obj,
976 uint32_t index,
977 v8::AccessType access_type) {
978 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000979 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000980 return false;
981 }
982
983 return true;
984}
985
986
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000987// Enumerator used as indices into the array returned from GetOwnProperty
988enum PropertyDescriptorIndices {
989 IS_ACCESSOR_INDEX,
990 VALUE_INDEX,
991 GETTER_INDEX,
992 SETTER_INDEX,
993 WRITABLE_INDEX,
994 ENUMERABLE_INDEX,
995 CONFIGURABLE_INDEX,
996 DESCRIPTOR_SIZE
997};
998
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000999
1000static MaybeObject* GetOwnProperty(Isolate* isolate,
1001 Handle<JSObject> obj,
1002 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001003 Heap* heap = isolate->heap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001004 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1005 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001006 LookupResult result(isolate);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001007 // This could be an element.
1008 uint32_t index;
1009 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001010 switch (obj->HasLocalElement(index)) {
1011 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001012 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001013
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001014 case JSObject::STRING_CHARACTER_ELEMENT: {
1015 // Special handling of string objects according to ECMAScript 5
1016 // 15.5.5.2. Note that this might be a string object with elements
1017 // other than the actual string value. This is covered by the
1018 // subsequent cases.
1019 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1020 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001021 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001022
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001023 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001024 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001025 elms->set(WRITABLE_INDEX, heap->false_value());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001026 elms->set(ENUMERABLE_INDEX, heap->true_value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001027 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001028 return *desc;
1029 }
1030
1031 case JSObject::INTERCEPTED_ELEMENT:
1032 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001033 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001034 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001035 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001036 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001037 elms->set(WRITABLE_INDEX, heap->true_value());
1038 elms->set(ENUMERABLE_INDEX, heap->true_value());
1039 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001040 return *desc;
1041 }
1042
1043 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001044 Handle<JSObject> holder = obj;
1045 if (obj->IsJSGlobalProxy()) {
1046 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001047 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001048 ASSERT(proto->IsJSGlobalObject());
1049 holder = Handle<JSObject>(JSObject::cast(proto));
1050 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001051 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001052 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001053 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001054 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001055 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001056 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001057 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001058 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001059 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001060 PropertyDetails details = dictionary->DetailsAt(entry);
1061 switch (details.type()) {
1062 case CALLBACKS: {
1063 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001064 AccessorPair* accessors =
1065 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001066 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001067 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001068 elms->set(GETTER_INDEX, accessors->GetComponent(ACCESSOR_GETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001069 }
1070 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001071 elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001072 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001073 break;
1074 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001075 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001076 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001077 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001078 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001079 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001080 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001081 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001082 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001083 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001084 default:
1085 UNREACHABLE();
1086 break;
1087 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001088 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1089 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001090 return *desc;
1091 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001092 }
1093 }
1094
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001095 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001096 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001097
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001098 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001099 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001100 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001101
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001102 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001103 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001104 }
1105
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001106 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1107 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001108
1109 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001110 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001111
1112 if (is_js_accessor) {
1113 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001114 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001115
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001116 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001117 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001118 elms->set(GETTER_INDEX, accessors->GetComponent(ACCESSOR_GETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001119 }
1120 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001121 elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001122 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001123 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001124 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1125 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001126
1127 PropertyAttributes attrs;
1128 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001129 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001130 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1131 if (!maybe_value->ToObject(&value)) return maybe_value;
1132 }
1133 elms->set(VALUE_INDEX, value);
1134 }
1135
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001136 return *desc;
1137}
1138
1139
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001140// Returns an array with the property description:
1141// if args[1] is not a property on args[0]
1142// returns undefined
1143// if args[1] is a data property on args[0]
1144// [false, value, Writeable, Enumerable, Configurable]
1145// if args[1] is an accessor on args[0]
1146// [true, GetFunction, SetFunction, Enumerable, Configurable]
1147RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
1148 ASSERT(args.length() == 2);
1149 HandleScope scope(isolate);
1150 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1151 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
1152 return GetOwnProperty(isolate, obj, name);
1153}
1154
1155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001156RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001157 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001158 CONVERT_ARG_CHECKED(JSObject, obj, 0);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001159 return obj->PreventExtensions();
1160}
1161
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001163RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001164 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001165 CONVERT_ARG_CHECKED(JSObject, obj, 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001166 if (obj->IsJSGlobalProxy()) {
1167 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001168 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001169 ASSERT(proto->IsJSGlobalObject());
1170 obj = JSObject::cast(proto);
1171 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001172 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001173}
1174
1175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001176RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001177 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001178 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001179 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
1180 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
1181 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001182 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1183 if (result.is_null()) return Failure::Exception();
1184 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185}
1186
1187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001188RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001189 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001191 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001192 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193}
1194
1195
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001196RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 ASSERT(args.length() == 1);
1198 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001199 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001200 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001201}
1202
1203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001204RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001206 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
1207 CONVERT_SMI_ARG_CHECKED(index, 1)
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001208 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1209 InstanceType type = templ->map()->instance_type();
1210 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1211 type == OBJECT_TEMPLATE_INFO_TYPE);
1212 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001213 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001214 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1215 } else {
1216 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1217 }
1218 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219}
1220
1221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001222RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001223 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001224 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001225 Map* old_map = object->map();
1226 bool needs_access_checks = old_map->is_access_check_needed();
1227 if (needs_access_checks) {
1228 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001229 Object* new_map;
1230 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1231 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1232 }
ager@chromium.org32912102009-01-16 10:38:43 +00001233
1234 Map::cast(new_map)->set_is_access_check_needed(false);
1235 object->set_map(Map::cast(new_map));
1236 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001237 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001238}
1239
1240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001241RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001242 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001243 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001244 Map* old_map = object->map();
1245 if (!old_map->is_access_check_needed()) {
1246 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001247 Object* new_map;
1248 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1249 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1250 }
ager@chromium.org32912102009-01-16 10:38:43 +00001251
1252 Map::cast(new_map)->set_is_access_check_needed(true);
1253 object->set_map(Map::cast(new_map));
1254 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001255 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001256}
1257
1258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001259static Failure* ThrowRedeclarationError(Isolate* isolate,
1260 const char* type,
1261 Handle<String> name) {
1262 HandleScope scope(isolate);
1263 Handle<Object> type_handle =
1264 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265 Handle<Object> args[2] = { type_handle, name };
1266 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1268 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269}
1270
1271
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001272RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001274 HandleScope scope(isolate);
1275 Handle<GlobalObject> global = Handle<GlobalObject>(
1276 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277
ager@chromium.org3811b432009-10-28 14:53:37 +00001278 Handle<Context> context = args.at<Context>(0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001279 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001280 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 // Traverse the name/value pairs and set the properties.
1283 int length = pairs->length();
1284 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001285 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001287 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288
1289 // We have to declare a global const property. To capture we only
1290 // assign to it when evaluating the assignment for "const x =
1291 // <expr>" the initial value is the hole.
1292 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001293 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 if (value->IsUndefined() || is_const_property) {
1295 // Lookup the property in the global object, and don't set the
1296 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001297 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298 global->Lookup(*name, &lookup);
1299 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 // We found an existing property. Unless it was an interceptor
1301 // that claims the property is absent, skip this declaration.
1302 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303 continue;
1304 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001305 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1306 if (attributes != ABSENT) {
1307 continue;
1308 }
1309 // Fall-through and introduce the absent property by using
1310 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311 }
1312 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001313 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001314 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001315 Handle<SharedFunctionInfo> shared =
1316 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001318 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1319 context,
1320 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321 value = function;
1322 }
1323
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001324 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325 global->LocalLookup(*name, &lookup);
1326
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001327 // Compute the property attributes. According to ECMA-262, section
1328 // 13, page 71, the property must be read-only and
1329 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1330 // property as read-only, so we don't either.
1331 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001332 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001333 attr |= DONT_DELETE;
1334 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001335 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001336 if (is_const_property || (is_native && is_function_declaration)) {
1337 attr |= READ_ONLY;
1338 }
1339
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001340 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1341
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001342 // Safari does not allow the invocation of callback setters for
1343 // function declarations. To mimic this behavior, we do not allow
1344 // the invocation of setters for function values. This makes a
1345 // difference for global functions with the same names as event
1346 // handlers such as "function onload() {}". Firefox does call the
1347 // onload setter in those case and Safari does not. We follow
1348 // Safari for compatibility.
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001349 if (is_function_declaration) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001350 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001351 // Do not overwrite READ_ONLY properties.
1352 if (lookup.GetAttributes() & READ_ONLY) {
1353 if (language_mode != CLASSIC_MODE) {
1354 Handle<Object> args[] = { name };
1355 return isolate->Throw(*isolate->factory()->NewTypeError(
1356 "strict_cannot_assign", HandleVector(args, ARRAY_SIZE(args))));
1357 }
1358 continue;
1359 }
1360 // Do not change DONT_DELETE to false from true.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001361 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001362 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001363 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1364
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001365 RETURN_IF_EMPTY_HANDLE(
1366 isolate,
1367 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1368 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001370 RETURN_IF_EMPTY_HANDLE(
1371 isolate,
1372 JSReceiver::SetProperty(global, name, value,
1373 static_cast<PropertyAttributes>(attr),
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001374 language_mode == CLASSIC_MODE
1375 ? kNonStrictMode : kStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376 }
1377 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001378
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001379 ASSERT(!isolate->has_pending_exception());
1380 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001381}
1382
1383
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001384RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001385 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001386 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001387
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001388 // Declarations are always made in a function or global context. In the
1389 // case of eval code, the context passed is the context of the caller,
1390 // which may be some nested context and not the declaration context.
1391 RUNTIME_ASSERT(args[0]->IsContext());
1392 Handle<Context> context(Context::cast(args[0])->declaration_context());
1393
ager@chromium.org7c537e22008-10-16 08:43:32 +00001394 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001395 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001396 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001397 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 int index;
1400 PropertyAttributes attributes;
1401 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001402 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001403 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001404 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001405
1406 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001407 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001408 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1409 // Functions are not read-only.
1410 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1411 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001412 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413 }
1414
1415 // Initialize it if necessary.
1416 if (*initial_value != NULL) {
1417 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001418 ASSERT(holder.is_identical_to(context));
1419 if (((attributes & READ_ONLY) == 0) ||
1420 context->get(index)->IsTheHole()) {
1421 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422 }
1423 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 // Slow case: The property is in the context extension object of a
1425 // function context or the global object of a global context.
1426 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001427 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001428 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001429 JSReceiver::SetProperty(object, name, initial_value, mode,
1430 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001431 }
1432 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001433
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001434 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001435 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001436 // "declared" in the function context's extension context or as a
1437 // property of the the global object.
1438 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001439 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001440 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001441 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001442 // Context extension objects are allocated lazily.
1443 ASSERT(context->IsFunctionContext());
1444 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001445 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001446 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001447 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001448 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449
ager@chromium.org7c537e22008-10-16 08:43:32 +00001450 // Declare the property by setting it to the initial value if provided,
1451 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1452 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001453 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001454 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001455 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001456 // Declaring a const context slot is a conflicting declaration if
1457 // there is a callback with that name in a prototype. It is
1458 // allowed to introduce const variables in
1459 // JSContextExtensionObjects. They are treated specially in
1460 // SetProperty and no setters are invoked for those since they are
1461 // not real JSObjects.
1462 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001463 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001464 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001465 object->Lookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001466 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001467 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001468 }
1469 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001470 RETURN_IF_EMPTY_HANDLE(
1471 isolate,
1472 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001473 }
1474
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001475 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001476}
1477
1478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001479RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001481 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001482 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001483 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484
1485 // Determine if we need to assign to the variable if it already
1486 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001487 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1488 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001490 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001491 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001492 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001493 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1494 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1495 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001496
1497 // According to ECMA-262, section 12.2, page 62, the property must
1498 // not be deletable.
1499 PropertyAttributes attributes = DONT_DELETE;
1500
1501 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001502 // there, there is a property with this name in the prototype chain.
1503 // We follow Safari and Firefox behavior and only set the property
1504 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001505 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001506 // Note that objects can have hidden prototypes, so we need to traverse
1507 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001508 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001509 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001510 while (object->IsJSObject() &&
1511 JSObject::cast(object)->map()->is_hidden_prototype()) {
1512 JSObject* raw_holder = JSObject::cast(object);
1513 raw_holder->LocalLookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001514 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001515 HandleScope handle_scope(isolate);
1516 Handle<JSObject> holder(raw_holder);
1517 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1518 // Update the raw pointer in case it's changed due to GC.
1519 raw_holder = *holder;
1520 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1521 // Found an interceptor that's not read only.
1522 if (assign) {
1523 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001524 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001525 } else {
1526 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001527 }
1528 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001529 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001530 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531 }
1532
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001533 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001534 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001535 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001536 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001537 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001538 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001539}
1540
1541
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001542RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 // All constants are declared with an initial value. The name
1544 // of the constant is the first argument and the initial value
1545 // is the second.
1546 RUNTIME_ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001547 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548 Handle<Object> value = args.at<Object>(1);
1549
1550 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001551 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001552
1553 // According to ECMA-262, section 12.2, page 62, the property must
1554 // not be deletable. Since it's a const, it must be READ_ONLY too.
1555 PropertyAttributes attributes =
1556 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1557
1558 // Lookup the property locally in the global object. If it isn't
1559 // there, we add the property and take special precautions to always
1560 // add it as a local property even in case of callbacks in the
1561 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001562 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001563 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564 global->LocalLookup(*name, &lookup);
1565 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001566 return global->SetLocalPropertyIgnoreAttributes(*name,
1567 *value,
1568 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001569 }
1570
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001571 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001573 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001574 HandleScope handle_scope(isolate);
1575 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001577 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578 // property through an interceptor and only do it if it's
1579 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001580 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001581 RETURN_IF_EMPTY_HANDLE(
1582 isolate,
1583 JSReceiver::SetProperty(global, name, value, attributes,
1584 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585 return *value;
1586 }
1587
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001588 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001589 // constant. For now, we determine this by checking if the
1590 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001591 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001592 PropertyType type = lookup.type();
1593 if (type == FIELD) {
1594 FixedArray* properties = global->properties();
1595 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001596 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001597 properties->set(index, *value);
1598 }
1599 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001600 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1601 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001602 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001603 }
1604 } else {
1605 // Ignore re-initialization of constants that have already been
1606 // assigned a function value.
1607 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1608 }
1609
1610 // Use the set value as the result of the operation.
1611 return *value;
1612}
1613
1614
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001615RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001616 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617 ASSERT(args.length() == 3);
1618
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001619 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001621
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001622 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001623 RUNTIME_ASSERT(args[1]->IsContext());
1624 Handle<Context> context(Context::cast(args[1])->declaration_context());
1625
1626 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627
1628 int index;
1629 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001630 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001631 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001632 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001633 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001634
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001636 ASSERT(holder->IsContext());
1637 // Property was found in a context. Perform the assignment if we
1638 // found some non-constant or an uninitialized constant.
1639 Handle<Context> context = Handle<Context>::cast(holder);
1640 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1641 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001642 }
1643 return *value;
1644 }
1645
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001646 // The property could not be found, we introduce it as a property of the
1647 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001648 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001649 Handle<JSObject> global = Handle<JSObject>(
1650 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001651 // Strict mode not needed (const disallowed in strict mode).
1652 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001653 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001654 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001655 return *value;
1656 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001657
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001658 // The property was present in some function's context extension object,
1659 // as a property on the subject of a with, or as a property of the global
1660 // object.
1661 //
1662 // In most situations, eval-introduced consts should still be present in
1663 // the context extension object. However, because declaration and
1664 // initialization are separate, the property might have been deleted
1665 // before we reach the initialization point.
1666 //
1667 // Example:
1668 //
1669 // function f() { eval("delete x; const x;"); }
1670 //
1671 // In that case, the initialization behaves like a normal assignment.
1672 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001673
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001674 if (*object == context->extension()) {
1675 // This is the property that was introduced by the const declaration.
1676 // Set it if it hasn't been set before. NOTE: We cannot use
1677 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001678 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001679 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001680 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001681 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1682
1683 PropertyType type = lookup.type();
1684 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001685 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001686 int index = lookup.GetFieldIndex();
1687 if (properties->get(index)->IsTheHole()) {
1688 properties->set(index, *value);
1689 }
1690 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001691 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1692 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001693 }
1694 } else {
1695 // We should not reach here. Any real, named property should be
1696 // either a field or a dictionary slot.
1697 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001698 }
1699 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001700 // The property was found on some other object. Set it if it is not a
1701 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001702 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001703 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001704 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001705 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001706 JSReceiver::SetProperty(object, name, value, attributes,
1707 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001708 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001709 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001710
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001711 return *value;
1712}
1713
1714
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001715RUNTIME_FUNCTION(MaybeObject*,
1716 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001717 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001718 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001719 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001720 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001721 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001722 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001723 }
1724 return *object;
1725}
1726
1727
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001728RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001729 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001730 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001731 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1732 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001733 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001734 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001735 CONVERT_SMI_ARG_CHECKED(index, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001736 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001737 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001738 RUNTIME_ASSERT(index >= 0);
1739 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001740 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001741 Handle<Object> result = RegExpImpl::Exec(regexp,
1742 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001743 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001744 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001745 if (result.is_null()) return Failure::Exception();
1746 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001747}
1748
1749
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001750RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001751 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001752 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001753 if (elements_count < 0 ||
1754 elements_count > FixedArray::kMaxLength ||
1755 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001756 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001757 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001758 Object* new_object;
1759 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001760 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001761 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1762 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001763 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001764 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1765 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001766 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1767 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001768 {
1769 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001770 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001771 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001772 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001773 }
1774 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001775 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001776 array->set_elements(elements);
1777 array->set_length(Smi::FromInt(elements_count));
1778 // Write in-object properties after the length of the array.
1779 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1780 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1781 return array;
1782}
1783
1784
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001785RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001786 AssertNoAllocation no_alloc;
1787 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001788 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1789 CONVERT_ARG_CHECKED(String, source, 1);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001790
1791 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001792 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001793
1794 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001795 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001796
1797 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001799
1800 Map* map = regexp->map();
1801 Object* constructor = map->constructor();
1802 if (constructor->IsJSFunction() &&
1803 JSFunction::cast(constructor)->initial_map() == map) {
1804 // If we still have the original map, set in-object properties directly.
1805 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001806 // Both true and false are immovable immortal objects so no need for write
1807 // barrier.
1808 regexp->InObjectPropertyAtPut(
1809 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1810 regexp->InObjectPropertyAtPut(
1811 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1812 regexp->InObjectPropertyAtPut(
1813 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001814 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1815 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001816 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001817 return regexp;
1818 }
1819
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001820 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001821 PropertyAttributes final =
1822 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1823 PropertyAttributes writable =
1824 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001825 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001826 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001827 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001828 source,
1829 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001830 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001831 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001832 global,
1833 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001834 ASSERT(!result->IsFailure());
1835 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001837 ignoreCase,
1838 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001839 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001841 multiline,
1842 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001843 ASSERT(!result->IsFailure());
1844 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001845 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001846 Smi::FromInt(0),
1847 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001848 ASSERT(!result->IsFailure());
1849 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001850 return regexp;
1851}
1852
1853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001854RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001855 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001856 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001857 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001858 // This is necessary to enable fast checks for absence of elements
1859 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001860 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001861 return Smi::FromInt(0);
1862}
1863
1864
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001865static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1866 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001867 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001868 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001869 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1870 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1871 Handle<JSFunction> optimized =
1872 isolate->factory()->NewFunction(key,
1873 JS_OBJECT_TYPE,
1874 JSObject::kHeaderSize,
1875 code,
1876 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001877 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001878 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001879 return optimized;
1880}
1881
1882
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001883RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001884 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001885 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001886 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001887
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001888 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1889 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1890 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1891 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1892 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1893 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1894 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001895
1896 return *holder;
1897}
1898
1899
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001900RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001901 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001902 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001903
1904 if (!callable->IsJSFunction()) {
1905 HandleScope scope(isolate);
1906 bool threw = false;
1907 Handle<Object> delegate =
1908 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1909 if (threw) return Failure::Exception();
1910 callable = JSFunction::cast(*delegate);
1911 }
1912 JSFunction* function = JSFunction::cast(callable);
1913
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001914 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001915 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001916 return isolate->heap()->undefined_value();
1917 }
1918 // Returns undefined for strict or native functions, or
1919 // the associated global receiver for "normal" functions.
1920
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001921 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001922 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001923 return global_context->global()->global_receiver();
1924}
1925
1926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001927RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001928 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001930 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001931 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001932 Handle<String> pattern = args.at<String>(2);
1933 Handle<String> flags = args.at<String>(3);
1934
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001935 // Get the RegExp function from the context in the literals array.
1936 // This is the RegExp function from the context in which the
1937 // function was created. We do not use the RegExp function from the
1938 // current global context because this might be the RegExp function
1939 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001940 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001941 Handle<JSFunction>(
1942 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001943 // Compute the regular expression literal.
1944 bool has_pending_exception;
1945 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001946 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1947 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001948 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001949 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001950 return Failure::Exception();
1951 }
1952 literals->set(index, *regexp);
1953 return *regexp;
1954}
1955
1956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001957RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001958 NoHandleAllocation ha;
1959 ASSERT(args.length() == 1);
1960
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001961 CONVERT_ARG_CHECKED(JSFunction, f, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001962 return f->shared()->name();
1963}
1964
1965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001966RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001967 NoHandleAllocation ha;
1968 ASSERT(args.length() == 2);
1969
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001970 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1971 CONVERT_ARG_CHECKED(String, name, 1);
ager@chromium.org236ad962008-09-25 09:45:57 +00001972 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001973 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001974}
1975
1976
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001977RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1978 NoHandleAllocation ha;
1979 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001980 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001981 return isolate->heap()->ToBoolean(
1982 f->shared()->name_should_print_as_anonymous());
1983}
1984
1985
1986RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1987 NoHandleAllocation ha;
1988 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001989 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001990 f->shared()->set_name_should_print_as_anonymous(true);
1991 return isolate->heap()->undefined_value();
1992}
1993
1994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001995RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001996 NoHandleAllocation ha;
1997 ASSERT(args.length() == 1);
1998
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001999 CONVERT_ARG_CHECKED(JSFunction, f, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002000 Object* obj = f->RemovePrototype();
2001 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002002
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002003 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002004}
2005
2006
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002007RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002008 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002009 ASSERT(args.length() == 1);
2010
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002011 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002012 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2013 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002014
2015 return *GetScriptWrapper(Handle<Script>::cast(script));
2016}
2017
2018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002019RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002020 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002021 ASSERT(args.length() == 1);
2022
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002023 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002024 Handle<SharedFunctionInfo> shared(f->shared());
2025 return *shared->GetSourceCode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002026}
2027
2028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002029RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002030 NoHandleAllocation ha;
2031 ASSERT(args.length() == 1);
2032
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002033 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002034 int pos = fun->shared()->start_position();
2035 return Smi::FromInt(pos);
2036}
2037
2038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002039RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002040 ASSERT(args.length() == 2);
2041
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002042 CONVERT_ARG_CHECKED(Code, code, 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002043 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2044
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002045 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2046
2047 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002048 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002049}
2050
2051
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002052RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002053 NoHandleAllocation ha;
2054 ASSERT(args.length() == 2);
2055
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002056 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2057 CONVERT_ARG_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002058 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002059 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002060}
2061
2062
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002063RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002064 NoHandleAllocation ha;
2065 ASSERT(args.length() == 2);
2066
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002067 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2068 CONVERT_SMI_ARG_CHECKED(length, 1);
2069 fun->shared()->set_length(length);
2070 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002071}
2072
2073
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002074RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002075 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002076 ASSERT(args.length() == 2);
2077
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002078 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002079 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002080 Object* obj;
2081 { MaybeObject* maybe_obj =
2082 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2083 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2084 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002085 return args[0]; // return TOS
2086}
2087
2088
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002089RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2090 NoHandleAllocation ha;
2091 RUNTIME_ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002092 CONVERT_ARG_CHECKED(JSFunction, function, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002093
2094 MaybeObject* maybe_name =
2095 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2096 String* name;
2097 if (!maybe_name->To(&name)) return maybe_name;
2098
2099 if (function->HasFastProperties()) {
2100 // Construct a new field descriptor with updated attributes.
2101 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2102 int index = instance_desc->Search(name);
2103 ASSERT(index != DescriptorArray::kNotFound);
2104 PropertyDetails details(instance_desc->GetDetails(index));
2105 CallbacksDescriptor new_desc(name,
2106 instance_desc->GetValue(index),
2107 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2108 details.index());
2109 // Construct a new field descriptors array containing the new descriptor.
2110 Object* descriptors_unchecked;
2111 { MaybeObject* maybe_descriptors_unchecked =
2112 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2113 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2114 return maybe_descriptors_unchecked;
2115 }
2116 }
2117 DescriptorArray* new_descriptors =
2118 DescriptorArray::cast(descriptors_unchecked);
2119 // Create a new map featuring the new field descriptors array.
2120 Object* map_unchecked;
2121 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2122 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2123 return maybe_map_unchecked;
2124 }
2125 }
2126 Map* new_map = Map::cast(map_unchecked);
2127 new_map->set_instance_descriptors(new_descriptors);
2128 function->set_map(new_map);
2129 } else { // Dictionary properties.
2130 // Directly manipulate the property details.
2131 int entry = function->property_dictionary()->FindEntry(name);
2132 ASSERT(entry != StringDictionary::kNotFound);
2133 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2134 PropertyDetails new_details(
2135 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2136 details.type(),
2137 details.index());
2138 function->property_dictionary()->DetailsAtPut(entry, new_details);
2139 }
2140 return function;
2141}
2142
2143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002144RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002145 NoHandleAllocation ha;
2146 ASSERT(args.length() == 1);
2147
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002148 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002149 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002150}
2151
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002153RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002154 NoHandleAllocation ha;
2155 ASSERT(args.length() == 1);
2156
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002157 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002158 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002159}
2160
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002161
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002162RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002163 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002164 ASSERT(args.length() == 2);
2165
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002166 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002167 Handle<Object> code = args.at<Object>(1);
2168
2169 Handle<Context> context(target->context());
2170
2171 if (!code->IsNull()) {
2172 RUNTIME_ASSERT(code->IsJSFunction());
2173 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002174 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002175
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002176 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002177 return Failure::Exception();
2178 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002179 // Since we don't store the source for this we should never
2180 // optimize this.
2181 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002182 // Set the code, scope info, formal parameter count,
2183 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002184 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002185 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002186 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002187 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002188 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002189 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002190 // Set the source code of the target function to undefined.
2191 // SetCode is only used for built-in constructors like String,
2192 // Array, and Object, and some web code
2193 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002194 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002195 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002196 // Clear the optimization hints related to the compiled code as these are no
2197 // longer valid when the code is overwritten.
2198 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002199 context = Handle<Context>(fun->context());
2200
2201 // Make sure we get a fresh copy of the literal vector to avoid
2202 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002203 int number_of_literals = fun->NumberOfLiterals();
2204 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002205 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002206 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002207 // Insert the object, regexp and array functions in the literals
2208 // array prefix. These are the functions that will be used when
2209 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002210 literals->set(JSFunction::kLiteralGlobalContextIndex,
2211 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002212 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002213 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002214 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002215
2216 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2217 isolate->logger()->LogExistingFunction(
2218 shared, Handle<Code>(shared->code()));
2219 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002220 }
2221
2222 target->set_context(*context);
2223 return *target;
2224}
2225
2226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002227RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002228 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002229 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002230 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002231 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002232 RUNTIME_ASSERT(num >= 0);
2233 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002234 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002235}
2236
2237
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002238MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2239 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002240 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002241 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002242 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002243 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002244 }
2245 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002246 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002247}
2248
2249
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002250RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002251 NoHandleAllocation ha;
2252 ASSERT(args.length() == 2);
2253
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002254 CONVERT_ARG_CHECKED(String, subject, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002255 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002256 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002257
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002258 uint32_t i = 0;
2259 if (index->IsSmi()) {
2260 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002261 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002262 i = value;
2263 } else {
2264 ASSERT(index->IsHeapNumber());
2265 double value = HeapNumber::cast(index)->value();
2266 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002267 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002268
2269 // Flatten the string. If someone wants to get a char at an index
2270 // in a cons string, it is likely that more indices will be
2271 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002272 Object* flat;
2273 { MaybeObject* maybe_flat = subject->TryFlatten();
2274 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2275 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002276 subject = String::cast(flat);
2277
2278 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002279 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002280 }
2281
2282 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002283}
2284
2285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002286RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002287 NoHandleAllocation ha;
2288 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002289 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002290}
2291
lrn@chromium.org25156de2010-04-06 13:10:27 +00002292
2293class FixedArrayBuilder {
2294 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002295 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2296 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002297 length_(0),
2298 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002299 // Require a non-zero initial size. Ensures that doubling the size to
2300 // extend the array will work.
2301 ASSERT(initial_capacity > 0);
2302 }
2303
2304 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2305 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002306 length_(0),
2307 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002308 // Require a non-zero initial size. Ensures that doubling the size to
2309 // extend the array will work.
2310 ASSERT(backing_store->length() > 0);
2311 }
2312
2313 bool HasCapacity(int elements) {
2314 int length = array_->length();
2315 int required_length = length_ + elements;
2316 return (length >= required_length);
2317 }
2318
2319 void EnsureCapacity(int elements) {
2320 int length = array_->length();
2321 int required_length = length_ + elements;
2322 if (length < required_length) {
2323 int new_length = length;
2324 do {
2325 new_length *= 2;
2326 } while (new_length < required_length);
2327 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002328 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002329 array_->CopyTo(0, *extended_array, 0, length_);
2330 array_ = extended_array;
2331 }
2332 }
2333
2334 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002335 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002336 ASSERT(length_ < capacity());
2337 array_->set(length_, value);
2338 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002339 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002340 }
2341
2342 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002343 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002344 ASSERT(length_ < capacity());
2345 array_->set(length_, value);
2346 length_++;
2347 }
2348
2349 Handle<FixedArray> array() {
2350 return array_;
2351 }
2352
2353 int length() {
2354 return length_;
2355 }
2356
2357 int capacity() {
2358 return array_->length();
2359 }
2360
2361 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002362 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002363 result_array->set_length(Smi::FromInt(length_));
2364 return result_array;
2365 }
2366
2367 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002368 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002369 target_array->set_length(Smi::FromInt(length_));
2370 return target_array;
2371 }
2372
2373 private:
2374 Handle<FixedArray> array_;
2375 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002376 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002377};
2378
2379
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002380// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002381const int kStringBuilderConcatHelperLengthBits = 11;
2382const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002383
2384template <typename schar>
2385static inline void StringBuilderConcatHelper(String*,
2386 schar*,
2387 FixedArray*,
2388 int);
2389
lrn@chromium.org25156de2010-04-06 13:10:27 +00002390typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2391 StringBuilderSubstringLength;
2392typedef BitField<int,
2393 kStringBuilderConcatHelperLengthBits,
2394 kStringBuilderConcatHelperPositionBits>
2395 StringBuilderSubstringPosition;
2396
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002397
2398class ReplacementStringBuilder {
2399 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002400 ReplacementStringBuilder(Heap* heap,
2401 Handle<String> subject,
2402 int estimated_part_count)
2403 : heap_(heap),
2404 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002405 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002406 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002407 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002408 // Require a non-zero initial size. Ensures that doubling the size to
2409 // extend the array will work.
2410 ASSERT(estimated_part_count > 0);
2411 }
2412
lrn@chromium.org25156de2010-04-06 13:10:27 +00002413 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2414 int from,
2415 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002416 ASSERT(from >= 0);
2417 int length = to - from;
2418 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002419 if (StringBuilderSubstringLength::is_valid(length) &&
2420 StringBuilderSubstringPosition::is_valid(from)) {
2421 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2422 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002423 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002424 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002425 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002426 builder->Add(Smi::FromInt(-length));
2427 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002428 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002429 }
2430
2431
2432 void EnsureCapacity(int elements) {
2433 array_builder_.EnsureCapacity(elements);
2434 }
2435
2436
2437 void AddSubjectSlice(int from, int to) {
2438 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002439 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002440 }
2441
2442
2443 void AddString(Handle<String> string) {
2444 int length = string->length();
2445 ASSERT(length > 0);
2446 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002447 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002448 is_ascii_ = false;
2449 }
2450 IncrementCharacterCount(length);
2451 }
2452
2453
2454 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002455 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002456 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002457 }
2458
2459 Handle<String> joined_string;
2460 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002461 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002462 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002463 char* char_buffer = seq->GetChars();
2464 StringBuilderConcatHelper(*subject_,
2465 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002466 *array_builder_.array(),
2467 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002468 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002469 } else {
2470 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002471 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002472 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002473 uc16* char_buffer = seq->GetChars();
2474 StringBuilderConcatHelper(*subject_,
2475 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002476 *array_builder_.array(),
2477 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002478 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002479 }
2480 return joined_string;
2481 }
2482
2483
2484 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002485 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002486 V8::FatalProcessOutOfMemory("String.replace result too large.");
2487 }
2488 character_count_ += by;
2489 }
2490
lrn@chromium.org25156de2010-04-06 13:10:27 +00002491 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002492 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002493 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002494
lrn@chromium.org25156de2010-04-06 13:10:27 +00002495 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002496 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2497 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002498 }
2499
2500
ager@chromium.org04921a82011-06-27 13:21:41 +00002501 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2502 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002503 }
2504
2505
2506 void AddElement(Object* element) {
2507 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002508 ASSERT(array_builder_.capacity() > array_builder_.length());
2509 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002510 }
2511
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002512 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002513 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002514 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002515 int character_count_;
2516 bool is_ascii_;
2517};
2518
2519
2520class CompiledReplacement {
2521 public:
2522 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002523 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002524
2525 void Compile(Handle<String> replacement,
2526 int capture_count,
2527 int subject_length);
2528
2529 void Apply(ReplacementStringBuilder* builder,
2530 int match_from,
2531 int match_to,
2532 Handle<JSArray> last_match_info);
2533
2534 // Number of distinct parts of the replacement pattern.
2535 int parts() {
2536 return parts_.length();
2537 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002538
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002539 bool simple_hint() {
2540 return simple_hint_;
2541 }
2542
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002543 private:
2544 enum PartType {
2545 SUBJECT_PREFIX = 1,
2546 SUBJECT_SUFFIX,
2547 SUBJECT_CAPTURE,
2548 REPLACEMENT_SUBSTRING,
2549 REPLACEMENT_STRING,
2550
2551 NUMBER_OF_PART_TYPES
2552 };
2553
2554 struct ReplacementPart {
2555 static inline ReplacementPart SubjectMatch() {
2556 return ReplacementPart(SUBJECT_CAPTURE, 0);
2557 }
2558 static inline ReplacementPart SubjectCapture(int capture_index) {
2559 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2560 }
2561 static inline ReplacementPart SubjectPrefix() {
2562 return ReplacementPart(SUBJECT_PREFIX, 0);
2563 }
2564 static inline ReplacementPart SubjectSuffix(int subject_length) {
2565 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2566 }
2567 static inline ReplacementPart ReplacementString() {
2568 return ReplacementPart(REPLACEMENT_STRING, 0);
2569 }
2570 static inline ReplacementPart ReplacementSubString(int from, int to) {
2571 ASSERT(from >= 0);
2572 ASSERT(to > from);
2573 return ReplacementPart(-from, to);
2574 }
2575
2576 // If tag <= 0 then it is the negation of a start index of a substring of
2577 // the replacement pattern, otherwise it's a value from PartType.
2578 ReplacementPart(int tag, int data)
2579 : tag(tag), data(data) {
2580 // Must be non-positive or a PartType value.
2581 ASSERT(tag < NUMBER_OF_PART_TYPES);
2582 }
2583 // Either a value of PartType or a non-positive number that is
2584 // the negation of an index into the replacement string.
2585 int tag;
2586 // The data value's interpretation depends on the value of tag:
2587 // tag == SUBJECT_PREFIX ||
2588 // tag == SUBJECT_SUFFIX: data is unused.
2589 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2590 // tag == REPLACEMENT_SUBSTRING ||
2591 // tag == REPLACEMENT_STRING: data is index into array of substrings
2592 // of the replacement string.
2593 // tag <= 0: Temporary representation of the substring of the replacement
2594 // string ranging over -tag .. data.
2595 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2596 // substring objects.
2597 int data;
2598 };
2599
2600 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002601 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002602 Vector<Char> characters,
2603 int capture_count,
2604 int subject_length) {
2605 int length = characters.length();
2606 int last = 0;
2607 for (int i = 0; i < length; i++) {
2608 Char c = characters[i];
2609 if (c == '$') {
2610 int next_index = i + 1;
2611 if (next_index == length) { // No next character!
2612 break;
2613 }
2614 Char c2 = characters[next_index];
2615 switch (c2) {
2616 case '$':
2617 if (i > last) {
2618 // There is a substring before. Include the first "$".
2619 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2620 last = next_index + 1; // Continue after the second "$".
2621 } else {
2622 // Let the next substring start with the second "$".
2623 last = next_index;
2624 }
2625 i = next_index;
2626 break;
2627 case '`':
2628 if (i > last) {
2629 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2630 }
2631 parts->Add(ReplacementPart::SubjectPrefix());
2632 i = next_index;
2633 last = i + 1;
2634 break;
2635 case '\'':
2636 if (i > last) {
2637 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2638 }
2639 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2640 i = next_index;
2641 last = i + 1;
2642 break;
2643 case '&':
2644 if (i > last) {
2645 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2646 }
2647 parts->Add(ReplacementPart::SubjectMatch());
2648 i = next_index;
2649 last = i + 1;
2650 break;
2651 case '0':
2652 case '1':
2653 case '2':
2654 case '3':
2655 case '4':
2656 case '5':
2657 case '6':
2658 case '7':
2659 case '8':
2660 case '9': {
2661 int capture_ref = c2 - '0';
2662 if (capture_ref > capture_count) {
2663 i = next_index;
2664 continue;
2665 }
2666 int second_digit_index = next_index + 1;
2667 if (second_digit_index < length) {
2668 // Peek ahead to see if we have two digits.
2669 Char c3 = characters[second_digit_index];
2670 if ('0' <= c3 && c3 <= '9') { // Double digits.
2671 int double_digit_ref = capture_ref * 10 + c3 - '0';
2672 if (double_digit_ref <= capture_count) {
2673 next_index = second_digit_index;
2674 capture_ref = double_digit_ref;
2675 }
2676 }
2677 }
2678 if (capture_ref > 0) {
2679 if (i > last) {
2680 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2681 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002682 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002683 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2684 last = next_index + 1;
2685 }
2686 i = next_index;
2687 break;
2688 }
2689 default:
2690 i = next_index;
2691 break;
2692 }
2693 }
2694 }
2695 if (length > last) {
2696 if (last == 0) {
2697 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002698 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002699 } else {
2700 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2701 }
2702 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002703 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002704 }
2705
2706 ZoneList<ReplacementPart> parts_;
2707 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002708 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002709};
2710
2711
2712void CompiledReplacement::Compile(Handle<String> replacement,
2713 int capture_count,
2714 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002715 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002716 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002717 String::FlatContent content = replacement->GetFlatContent();
2718 ASSERT(content.IsFlat());
2719 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002720 simple_hint_ = ParseReplacementPattern(&parts_,
2721 content.ToAsciiVector(),
2722 capture_count,
2723 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002724 } else {
2725 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002726 simple_hint_ = ParseReplacementPattern(&parts_,
2727 content.ToUC16Vector(),
2728 capture_count,
2729 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002730 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002731 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002732 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002733 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002734 int substring_index = 0;
2735 for (int i = 0, n = parts_.length(); i < n; i++) {
2736 int tag = parts_[i].tag;
2737 if (tag <= 0) { // A replacement string slice.
2738 int from = -tag;
2739 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002740 replacement_substrings_.Add(
2741 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002742 parts_[i].tag = REPLACEMENT_SUBSTRING;
2743 parts_[i].data = substring_index;
2744 substring_index++;
2745 } else if (tag == REPLACEMENT_STRING) {
2746 replacement_substrings_.Add(replacement);
2747 parts_[i].data = substring_index;
2748 substring_index++;
2749 }
2750 }
2751}
2752
2753
2754void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2755 int match_from,
2756 int match_to,
2757 Handle<JSArray> last_match_info) {
2758 for (int i = 0, n = parts_.length(); i < n; i++) {
2759 ReplacementPart part = parts_[i];
2760 switch (part.tag) {
2761 case SUBJECT_PREFIX:
2762 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2763 break;
2764 case SUBJECT_SUFFIX: {
2765 int subject_length = part.data;
2766 if (match_to < subject_length) {
2767 builder->AddSubjectSlice(match_to, subject_length);
2768 }
2769 break;
2770 }
2771 case SUBJECT_CAPTURE: {
2772 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002773 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002774 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2775 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2776 if (from >= 0 && to > from) {
2777 builder->AddSubjectSlice(from, to);
2778 }
2779 break;
2780 }
2781 case REPLACEMENT_SUBSTRING:
2782 case REPLACEMENT_STRING:
2783 builder->AddString(replacement_substrings_[part.data]);
2784 break;
2785 default:
2786 UNREACHABLE();
2787 }
2788 }
2789}
2790
2791
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002792void FindAsciiStringIndices(Vector<const char> subject,
2793 char pattern,
2794 ZoneList<int>* indices,
2795 unsigned int limit) {
2796 ASSERT(limit > 0);
2797 // Collect indices of pattern in subject using memchr.
2798 // Stop after finding at most limit values.
2799 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2800 const char* subject_end = subject_start + subject.length();
2801 const char* pos = subject_start;
2802 while (limit > 0) {
2803 pos = reinterpret_cast<const char*>(
2804 memchr(pos, pattern, subject_end - pos));
2805 if (pos == NULL) return;
2806 indices->Add(static_cast<int>(pos - subject_start));
2807 pos++;
2808 limit--;
2809 }
2810}
2811
2812
2813template <typename SubjectChar, typename PatternChar>
2814void FindStringIndices(Isolate* isolate,
2815 Vector<const SubjectChar> subject,
2816 Vector<const PatternChar> pattern,
2817 ZoneList<int>* indices,
2818 unsigned int limit) {
2819 ASSERT(limit > 0);
2820 // Collect indices of pattern in subject.
2821 // Stop after finding at most limit values.
2822 int pattern_length = pattern.length();
2823 int index = 0;
2824 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2825 while (limit > 0) {
2826 index = search.Search(subject, index);
2827 if (index < 0) return;
2828 indices->Add(index);
2829 index += pattern_length;
2830 limit--;
2831 }
2832}
2833
2834
2835void FindStringIndicesDispatch(Isolate* isolate,
2836 String* subject,
2837 String* pattern,
2838 ZoneList<int>* indices,
2839 unsigned int limit) {
2840 {
2841 AssertNoAllocation no_gc;
2842 String::FlatContent subject_content = subject->GetFlatContent();
2843 String::FlatContent pattern_content = pattern->GetFlatContent();
2844 ASSERT(subject_content.IsFlat());
2845 ASSERT(pattern_content.IsFlat());
2846 if (subject_content.IsAscii()) {
2847 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2848 if (pattern_content.IsAscii()) {
2849 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2850 if (pattern_vector.length() == 1) {
2851 FindAsciiStringIndices(subject_vector,
2852 pattern_vector[0],
2853 indices,
2854 limit);
2855 } else {
2856 FindStringIndices(isolate,
2857 subject_vector,
2858 pattern_vector,
2859 indices,
2860 limit);
2861 }
2862 } else {
2863 FindStringIndices(isolate,
2864 subject_vector,
2865 pattern_content.ToUC16Vector(),
2866 indices,
2867 limit);
2868 }
2869 } else {
2870 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002871 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002872 FindStringIndices(isolate,
2873 subject_vector,
2874 pattern_content.ToAsciiVector(),
2875 indices,
2876 limit);
2877 } else {
2878 FindStringIndices(isolate,
2879 subject_vector,
2880 pattern_content.ToUC16Vector(),
2881 indices,
2882 limit);
2883 }
2884 }
2885 }
2886}
2887
2888
2889template<typename ResultSeqString>
2890MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2891 Isolate* isolate,
2892 Handle<String> subject,
2893 Handle<JSRegExp> pattern_regexp,
2894 Handle<String> replacement) {
2895 ASSERT(subject->IsFlat());
2896 ASSERT(replacement->IsFlat());
2897
2898 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2899 ZoneList<int> indices(8);
2900 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2901 String* pattern =
2902 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2903 int subject_len = subject->length();
2904 int pattern_len = pattern->length();
2905 int replacement_len = replacement->length();
2906
2907 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2908
2909 int matches = indices.length();
2910 if (matches == 0) return *subject;
2911
2912 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2913 int subject_pos = 0;
2914 int result_pos = 0;
2915
2916 Handle<ResultSeqString> result;
2917 if (ResultSeqString::kHasAsciiEncoding) {
2918 result = Handle<ResultSeqString>::cast(
2919 isolate->factory()->NewRawAsciiString(result_len));
2920 } else {
2921 result = Handle<ResultSeqString>::cast(
2922 isolate->factory()->NewRawTwoByteString(result_len));
2923 }
2924
2925 for (int i = 0; i < matches; i++) {
2926 // Copy non-matched subject content.
2927 if (subject_pos < indices.at(i)) {
2928 String::WriteToFlat(*subject,
2929 result->GetChars() + result_pos,
2930 subject_pos,
2931 indices.at(i));
2932 result_pos += indices.at(i) - subject_pos;
2933 }
2934
2935 // Replace match.
2936 if (replacement_len > 0) {
2937 String::WriteToFlat(*replacement,
2938 result->GetChars() + result_pos,
2939 0,
2940 replacement_len);
2941 result_pos += replacement_len;
2942 }
2943
2944 subject_pos = indices.at(i) + pattern_len;
2945 }
2946 // Add remaining subject content at the end.
2947 if (subject_pos < subject_len) {
2948 String::WriteToFlat(*subject,
2949 result->GetChars() + result_pos,
2950 subject_pos,
2951 subject_len);
2952 }
2953 return *result;
2954}
2955
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002956
lrn@chromium.org303ada72010-10-27 09:33:13 +00002957MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002958 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002959 String* subject,
2960 JSRegExp* regexp,
2961 String* replacement,
2962 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002963 ASSERT(subject->IsFlat());
2964 ASSERT(replacement->IsFlat());
2965
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002966 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002967
2968 int length = subject->length();
2969 Handle<String> subject_handle(subject);
2970 Handle<JSRegExp> regexp_handle(regexp);
2971 Handle<String> replacement_handle(replacement);
2972 Handle<JSArray> last_match_info_handle(last_match_info);
2973 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2974 subject_handle,
2975 0,
2976 last_match_info_handle);
2977 if (match.is_null()) {
2978 return Failure::Exception();
2979 }
2980 if (match->IsNull()) {
2981 return *subject_handle;
2982 }
2983
2984 int capture_count = regexp_handle->CaptureCount();
2985
2986 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002987 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002988 CompiledReplacement compiled_replacement;
2989 compiled_replacement.Compile(replacement_handle,
2990 capture_count,
2991 length);
2992
2993 bool is_global = regexp_handle->GetFlags().is_global();
2994
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002995 // Shortcut for simple non-regexp global replacements
2996 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002997 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002998 compiled_replacement.simple_hint()) {
2999 if (subject_handle->HasOnlyAsciiChars() &&
3000 replacement_handle->HasOnlyAsciiChars()) {
3001 return StringReplaceStringWithString<SeqAsciiString>(
3002 isolate, subject_handle, regexp_handle, replacement_handle);
3003 } else {
3004 return StringReplaceStringWithString<SeqTwoByteString>(
3005 isolate, subject_handle, regexp_handle, replacement_handle);
3006 }
3007 }
3008
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003009 // Guessing the number of parts that the final result string is built
3010 // from. Global regexps can match any number of times, so we guess
3011 // conservatively.
3012 int expected_parts =
3013 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003014 ReplacementStringBuilder builder(isolate->heap(),
3015 subject_handle,
3016 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003017
3018 // Index of end of last match.
3019 int prev = 0;
3020
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003021 // Number of parts added by compiled replacement plus preceeding
3022 // string and possibly suffix after last match. It is possible for
3023 // all components to use two elements when encoded as two smis.
3024 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003025 bool matched = true;
3026 do {
3027 ASSERT(last_match_info_handle->HasFastElements());
3028 // Increase the capacity of the builder before entering local handle-scope,
3029 // so its internal buffer can safely allocate a new handle if it grows.
3030 builder.EnsureCapacity(parts_added_per_loop);
3031
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003032 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003033 int start, end;
3034 {
3035 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003036 FixedArray* match_info_array =
3037 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003038
3039 ASSERT_EQ(capture_count * 2 + 2,
3040 RegExpImpl::GetLastCaptureCount(match_info_array));
3041 start = RegExpImpl::GetCapture(match_info_array, 0);
3042 end = RegExpImpl::GetCapture(match_info_array, 1);
3043 }
3044
3045 if (prev < start) {
3046 builder.AddSubjectSlice(prev, start);
3047 }
3048 compiled_replacement.Apply(&builder,
3049 start,
3050 end,
3051 last_match_info_handle);
3052 prev = end;
3053
3054 // Only continue checking for global regexps.
3055 if (!is_global) break;
3056
3057 // Continue from where the match ended, unless it was an empty match.
3058 int next = end;
3059 if (start == end) {
3060 next = end + 1;
3061 if (next > length) break;
3062 }
3063
3064 match = RegExpImpl::Exec(regexp_handle,
3065 subject_handle,
3066 next,
3067 last_match_info_handle);
3068 if (match.is_null()) {
3069 return Failure::Exception();
3070 }
3071 matched = !match->IsNull();
3072 } while (matched);
3073
3074 if (prev < length) {
3075 builder.AddSubjectSlice(prev, length);
3076 }
3077
3078 return *(builder.ToString());
3079}
3080
3081
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003082template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003083MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003084 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003085 String* subject,
3086 JSRegExp* regexp,
3087 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003088 ASSERT(subject->IsFlat());
3089
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003090 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003091
3092 Handle<String> subject_handle(subject);
3093 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003094
3095 // Shortcut for simple non-regexp global replacements
3096 if (regexp_handle->GetFlags().is_global() &&
3097 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3098 Handle<String> empty_string_handle(HEAP->empty_string());
3099 if (subject_handle->HasOnlyAsciiChars()) {
3100 return StringReplaceStringWithString<SeqAsciiString>(
3101 isolate, subject_handle, regexp_handle, empty_string_handle);
3102 } else {
3103 return StringReplaceStringWithString<SeqTwoByteString>(
3104 isolate, subject_handle, regexp_handle, empty_string_handle);
3105 }
3106 }
3107
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003108 Handle<JSArray> last_match_info_handle(last_match_info);
3109 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3110 subject_handle,
3111 0,
3112 last_match_info_handle);
3113 if (match.is_null()) return Failure::Exception();
3114 if (match->IsNull()) return *subject_handle;
3115
3116 ASSERT(last_match_info_handle->HasFastElements());
3117
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003118 int start, end;
3119 {
3120 AssertNoAllocation match_info_array_is_not_in_a_handle;
3121 FixedArray* match_info_array =
3122 FixedArray::cast(last_match_info_handle->elements());
3123
3124 start = RegExpImpl::GetCapture(match_info_array, 0);
3125 end = RegExpImpl::GetCapture(match_info_array, 1);
3126 }
3127
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003128 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003129 int new_length = length - (end - start);
3130 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003131 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003132 }
3133 Handle<ResultSeqString> answer;
3134 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003135 answer = Handle<ResultSeqString>::cast(
3136 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003137 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003138 answer = Handle<ResultSeqString>::cast(
3139 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003140 }
3141
3142 // If the regexp isn't global, only match once.
3143 if (!regexp_handle->GetFlags().is_global()) {
3144 if (start > 0) {
3145 String::WriteToFlat(*subject_handle,
3146 answer->GetChars(),
3147 0,
3148 start);
3149 }
3150 if (end < length) {
3151 String::WriteToFlat(*subject_handle,
3152 answer->GetChars() + start,
3153 end,
3154 length);
3155 }
3156 return *answer;
3157 }
3158
3159 int prev = 0; // Index of end of last match.
3160 int next = 0; // Start of next search (prev unless last match was empty).
3161 int position = 0;
3162
3163 do {
3164 if (prev < start) {
3165 // Add substring subject[prev;start] to answer string.
3166 String::WriteToFlat(*subject_handle,
3167 answer->GetChars() + position,
3168 prev,
3169 start);
3170 position += start - prev;
3171 }
3172 prev = end;
3173 next = end;
3174 // Continue from where the match ended, unless it was an empty match.
3175 if (start == end) {
3176 next++;
3177 if (next > length) break;
3178 }
3179 match = RegExpImpl::Exec(regexp_handle,
3180 subject_handle,
3181 next,
3182 last_match_info_handle);
3183 if (match.is_null()) return Failure::Exception();
3184 if (match->IsNull()) break;
3185
3186 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003187 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003188 {
3189 AssertNoAllocation match_info_array_is_not_in_a_handle;
3190 FixedArray* match_info_array =
3191 FixedArray::cast(last_match_info_handle->elements());
3192 start = RegExpImpl::GetCapture(match_info_array, 0);
3193 end = RegExpImpl::GetCapture(match_info_array, 1);
3194 }
3195 } while (true);
3196
3197 if (prev < length) {
3198 // Add substring subject[prev;length] to answer string.
3199 String::WriteToFlat(*subject_handle,
3200 answer->GetChars() + position,
3201 prev,
3202 length);
3203 position += length - prev;
3204 }
3205
3206 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003207 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003208 }
3209
3210 // Shorten string and fill
3211 int string_size = ResultSeqString::SizeFor(position);
3212 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3213 int delta = allocated_string_size - string_size;
3214
3215 answer->set_length(position);
3216 if (delta == 0) return *answer;
3217
3218 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003219 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003220 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003221 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003222 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003223
3224 return *answer;
3225}
3226
3227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003228RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003229 ASSERT(args.length() == 4);
3230
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003231 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003232 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003233 Object* flat_subject;
3234 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3235 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3236 return maybe_flat_subject;
3237 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003238 }
3239 subject = String::cast(flat_subject);
3240 }
3241
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003242 CONVERT_ARG_CHECKED(String, replacement, 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003243 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003244 Object* flat_replacement;
3245 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3246 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3247 return maybe_flat_replacement;
3248 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003249 }
3250 replacement = String::cast(flat_replacement);
3251 }
3252
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003253 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3254 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003255
3256 ASSERT(last_match_info->HasFastElements());
3257
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003258 if (replacement->length() == 0) {
3259 if (subject->HasOnlyAsciiChars()) {
3260 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003261 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003262 } else {
3263 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003264 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003265 }
3266 }
3267
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003268 return StringReplaceRegExpWithString(isolate,
3269 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003270 regexp,
3271 replacement,
3272 last_match_info);
3273}
3274
3275
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003276Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3277 Handle<String> subject,
3278 Handle<String> search,
3279 Handle<String> replace,
3280 bool* found,
3281 int recursion_limit) {
3282 if (recursion_limit == 0) return Handle<String>::null();
3283 if (subject->IsConsString()) {
3284 ConsString* cons = ConsString::cast(*subject);
3285 Handle<String> first = Handle<String>(cons->first());
3286 Handle<String> second = Handle<String>(cons->second());
3287 Handle<String> new_first =
3288 StringReplaceOneCharWithString(isolate,
3289 first,
3290 search,
3291 replace,
3292 found,
3293 recursion_limit - 1);
3294 if (*found) return isolate->factory()->NewConsString(new_first, second);
3295 if (new_first.is_null()) return new_first;
3296
3297 Handle<String> new_second =
3298 StringReplaceOneCharWithString(isolate,
3299 second,
3300 search,
3301 replace,
3302 found,
3303 recursion_limit - 1);
3304 if (*found) return isolate->factory()->NewConsString(first, new_second);
3305 if (new_second.is_null()) return new_second;
3306
3307 return subject;
3308 } else {
3309 int index = StringMatch(isolate, subject, search, 0);
3310 if (index == -1) return subject;
3311 *found = true;
3312 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3313 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3314 Handle<String> second =
3315 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3316 return isolate->factory()->NewConsString(cons1, second);
3317 }
3318}
3319
3320
3321RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3322 ASSERT(args.length() == 3);
3323 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003324 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3325 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
3326 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003327
3328 // If the cons string tree is too deep, we simply abort the recursion and
3329 // retry with a flattened subject string.
3330 const int kRecursionLimit = 0x1000;
3331 bool found = false;
3332 Handle<String> result =
3333 Runtime::StringReplaceOneCharWithString(isolate,
3334 subject,
3335 search,
3336 replace,
3337 &found,
3338 kRecursionLimit);
3339 if (!result.is_null()) return *result;
3340 return *Runtime::StringReplaceOneCharWithString(isolate,
3341 FlattenGetString(subject),
3342 search,
3343 replace,
3344 &found,
3345 kRecursionLimit);
3346}
3347
3348
ager@chromium.org7c537e22008-10-16 08:43:32 +00003349// Perform string match of pattern on subject, starting at start index.
3350// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003351// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003352int Runtime::StringMatch(Isolate* isolate,
3353 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003354 Handle<String> pat,
3355 int start_index) {
3356 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003357 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003358
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003359 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003360 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003361
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003362 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003363 if (start_index + pattern_length > subject_length) return -1;
3364
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003365 if (!sub->IsFlat()) FlattenString(sub);
3366 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003367
ager@chromium.org7c537e22008-10-16 08:43:32 +00003368 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003369 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003370 String::FlatContent seq_sub = sub->GetFlatContent();
3371 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003372
ager@chromium.org7c537e22008-10-16 08:43:32 +00003373 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003374 if (seq_pat.IsAscii()) {
3375 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3376 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003377 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003378 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003379 pat_vector,
3380 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003381 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003382 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003383 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003384 pat_vector,
3385 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003386 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003387 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3388 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003389 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003390 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003391 pat_vector,
3392 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003393 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003394 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003395 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003396 pat_vector,
3397 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003398}
3399
3400
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003401RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003402 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003403 ASSERT(args.length() == 3);
3404
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003405 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3406 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003407
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003408 Object* index = args[2];
3409 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003410 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003411
ager@chromium.org870a0b62008-11-04 11:43:05 +00003412 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003413 int position =
3414 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003415 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003416}
3417
3418
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003419template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003420static int StringMatchBackwards(Vector<const schar> subject,
3421 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003422 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003423 int pattern_length = pattern.length();
3424 ASSERT(pattern_length >= 1);
3425 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003426
3427 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003428 for (int i = 0; i < pattern_length; i++) {
3429 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003430 if (c > String::kMaxAsciiCharCode) {
3431 return -1;
3432 }
3433 }
3434 }
3435
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003436 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003437 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003438 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003439 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003440 while (j < pattern_length) {
3441 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003442 break;
3443 }
3444 j++;
3445 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003446 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003447 return i;
3448 }
3449 }
3450 return -1;
3451}
3452
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003453RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003454 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003455 ASSERT(args.length() == 3);
3456
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003457 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3458 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003459
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003460 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003461 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003462 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003463
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003464 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003465 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003466
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003467 if (start_index + pat_length > sub_length) {
3468 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003469 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003470
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003471 if (pat_length == 0) {
3472 return Smi::FromInt(start_index);
3473 }
3474
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003475 if (!sub->IsFlat()) FlattenString(sub);
3476 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003477
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003478 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003479 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3480
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003481 String::FlatContent sub_content = sub->GetFlatContent();
3482 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003483
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003484 if (pat_content.IsAscii()) {
3485 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3486 if (sub_content.IsAscii()) {
3487 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003488 pat_vector,
3489 start_index);
3490 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003491 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003492 pat_vector,
3493 start_index);
3494 }
3495 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003496 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3497 if (sub_content.IsAscii()) {
3498 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003499 pat_vector,
3500 start_index);
3501 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003502 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003503 pat_vector,
3504 start_index);
3505 }
3506 }
3507
3508 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003509}
3510
3511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003512RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003513 NoHandleAllocation ha;
3514 ASSERT(args.length() == 2);
3515
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003516 CONVERT_ARG_CHECKED(String, str1, 0);
3517 CONVERT_ARG_CHECKED(String, str2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003518
3519 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003520 int str1_length = str1->length();
3521 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003522
3523 // Decide trivial cases without flattening.
3524 if (str1_length == 0) {
3525 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3526 return Smi::FromInt(-str2_length);
3527 } else {
3528 if (str2_length == 0) return Smi::FromInt(str1_length);
3529 }
3530
3531 int end = str1_length < str2_length ? str1_length : str2_length;
3532
3533 // No need to flatten if we are going to find the answer on the first
3534 // character. At this point we know there is at least one character
3535 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003536 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003537 if (d != 0) return Smi::FromInt(d);
3538
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003539 str1->TryFlatten();
3540 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003541
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003542 StringInputBuffer& buf1 =
3543 *isolate->runtime_state()->string_locale_compare_buf1();
3544 StringInputBuffer& buf2 =
3545 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003546
3547 buf1.Reset(str1);
3548 buf2.Reset(str2);
3549
3550 for (int i = 0; i < end; i++) {
3551 uint16_t char1 = buf1.GetNext();
3552 uint16_t char2 = buf2.GetNext();
3553 if (char1 != char2) return Smi::FromInt(char1 - char2);
3554 }
3555
3556 return Smi::FromInt(str1_length - str2_length);
3557}
3558
3559
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003560RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003561 NoHandleAllocation ha;
3562 ASSERT(args.length() == 3);
3563
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003564 CONVERT_ARG_CHECKED(String, value, 0);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003565 int start, end;
3566 // We have a fast integer-only case here to avoid a conversion to double in
3567 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003568 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3569 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3570 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3571 start = from_number;
3572 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003573 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003574 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3575 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003576 start = FastD2I(from_number);
3577 end = FastD2I(to_number);
3578 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003579 RUNTIME_ASSERT(end >= start);
3580 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003581 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003582 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003583 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003584}
3585
3586
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003587RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003588 ASSERT_EQ(3, args.length());
3589
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003590 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3591 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3592 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
ager@chromium.org41826e72009-03-30 13:30:57 +00003593 HandleScope handles;
3594
3595 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3596
3597 if (match.is_null()) {
3598 return Failure::Exception();
3599 }
3600 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003601 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003602 }
3603 int length = subject->length();
3604
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003605 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003606 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003607 int start;
3608 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003609 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003610 {
3611 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003612 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003613 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3614 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3615 }
3616 offsets.Add(start);
3617 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003618 if (start == end) if (++end > length) break;
3619 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003620 if (match.is_null()) {
3621 return Failure::Exception();
3622 }
3623 } while (!match->IsNull());
3624 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003625 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003626 Handle<String> substring = isolate->factory()->
3627 NewSubString(subject, offsets.at(0), offsets.at(1));
3628 elements->set(0, *substring);
3629 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003630 int from = offsets.at(i * 2);
3631 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003632 Handle<String> substring = isolate->factory()->
3633 NewProperSubString(subject, from, to);
3634 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003635 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003636 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003637 result->set_length(Smi::FromInt(matches));
3638 return *result;
3639}
3640
3641
lrn@chromium.org25156de2010-04-06 13:10:27 +00003642// Two smis before and after the match, for very long strings.
3643const int kMaxBuilderEntriesPerRegExpMatch = 5;
3644
3645
3646static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3647 Handle<JSArray> last_match_info,
3648 int match_start,
3649 int match_end) {
3650 // Fill last_match_info with a single capture.
3651 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3652 AssertNoAllocation no_gc;
3653 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3654 RegExpImpl::SetLastCaptureCount(elements, 2);
3655 RegExpImpl::SetLastInput(elements, *subject);
3656 RegExpImpl::SetLastSubject(elements, *subject);
3657 RegExpImpl::SetCapture(elements, 0, match_start);
3658 RegExpImpl::SetCapture(elements, 1, match_end);
3659}
3660
3661
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003662template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003663static bool SearchStringMultiple(Isolate* isolate,
3664 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003665 Vector<const PatternChar> pattern,
3666 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003667 FixedArrayBuilder* builder,
3668 int* match_pos) {
3669 int pos = *match_pos;
3670 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003671 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003672 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003673 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003674 while (pos <= max_search_start) {
3675 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3676 *match_pos = pos;
3677 return false;
3678 }
3679 // Position of end of previous match.
3680 int match_end = pos + pattern_length;
3681 int new_pos = search.Search(subject, match_end);
3682 if (new_pos >= 0) {
3683 // A match.
3684 if (new_pos > match_end) {
3685 ReplacementStringBuilder::AddSubjectSlice(builder,
3686 match_end,
3687 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003688 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003689 pos = new_pos;
3690 builder->Add(pattern_string);
3691 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003692 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003693 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003694 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003695
lrn@chromium.org25156de2010-04-06 13:10:27 +00003696 if (pos < max_search_start) {
3697 ReplacementStringBuilder::AddSubjectSlice(builder,
3698 pos + pattern_length,
3699 subject_length);
3700 }
3701 *match_pos = pos;
3702 return true;
3703}
3704
3705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003706static bool SearchStringMultiple(Isolate* isolate,
3707 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003708 Handle<String> pattern,
3709 Handle<JSArray> last_match_info,
3710 FixedArrayBuilder* builder) {
3711 ASSERT(subject->IsFlat());
3712 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003713
3714 // Treating as if a previous match was before first character.
3715 int match_pos = -pattern->length();
3716
3717 for (;;) { // Break when search complete.
3718 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3719 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003720 String::FlatContent subject_content = subject->GetFlatContent();
3721 String::FlatContent pattern_content = pattern->GetFlatContent();
3722 if (subject_content.IsAscii()) {
3723 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3724 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003725 if (SearchStringMultiple(isolate,
3726 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003727 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003728 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003729 builder,
3730 &match_pos)) break;
3731 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003732 if (SearchStringMultiple(isolate,
3733 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003734 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003735 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003736 builder,
3737 &match_pos)) break;
3738 }
3739 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003740 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3741 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003742 if (SearchStringMultiple(isolate,
3743 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003744 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003745 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003746 builder,
3747 &match_pos)) break;
3748 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003749 if (SearchStringMultiple(isolate,
3750 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003751 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003752 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003753 builder,
3754 &match_pos)) break;
3755 }
3756 }
3757 }
3758
3759 if (match_pos >= 0) {
3760 SetLastMatchInfoNoCaptures(subject,
3761 last_match_info,
3762 match_pos,
3763 match_pos + pattern->length());
3764 return true;
3765 }
3766 return false; // No matches at all.
3767}
3768
3769
3770static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003771 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003772 Handle<String> subject,
3773 Handle<JSRegExp> regexp,
3774 Handle<JSArray> last_match_array,
3775 FixedArrayBuilder* builder) {
3776 ASSERT(subject->IsFlat());
3777 int match_start = -1;
3778 int match_end = 0;
3779 int pos = 0;
3780 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3781 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3782
ulan@chromium.org812308e2012-02-29 15:58:45 +00003783 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003784 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003785 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003786 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003787
3788 for (;;) { // Break on failure, return on exception.
3789 RegExpImpl::IrregexpResult result =
3790 RegExpImpl::IrregexpExecOnce(regexp,
3791 subject,
3792 pos,
3793 register_vector);
3794 if (result == RegExpImpl::RE_SUCCESS) {
3795 match_start = register_vector[0];
3796 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3797 if (match_end < match_start) {
3798 ReplacementStringBuilder::AddSubjectSlice(builder,
3799 match_end,
3800 match_start);
3801 }
3802 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003803 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003804 if (!first) {
3805 builder->Add(*isolate->factory()->NewProperSubString(subject,
3806 match_start,
3807 match_end));
3808 } else {
3809 builder->Add(*isolate->factory()->NewSubString(subject,
3810 match_start,
3811 match_end));
3812 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003813 if (match_start != match_end) {
3814 pos = match_end;
3815 } else {
3816 pos = match_end + 1;
3817 if (pos > subject_length) break;
3818 }
3819 } else if (result == RegExpImpl::RE_FAILURE) {
3820 break;
3821 } else {
3822 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3823 return result;
3824 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003825 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003826 }
3827
3828 if (match_start >= 0) {
3829 if (match_end < subject_length) {
3830 ReplacementStringBuilder::AddSubjectSlice(builder,
3831 match_end,
3832 subject_length);
3833 }
3834 SetLastMatchInfoNoCaptures(subject,
3835 last_match_array,
3836 match_start,
3837 match_end);
3838 return RegExpImpl::RE_SUCCESS;
3839 } else {
3840 return RegExpImpl::RE_FAILURE; // No matches at all.
3841 }
3842}
3843
3844
3845static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003846 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003847 Handle<String> subject,
3848 Handle<JSRegExp> regexp,
3849 Handle<JSArray> last_match_array,
3850 FixedArrayBuilder* builder) {
3851
3852 ASSERT(subject->IsFlat());
3853 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3854 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3855
ulan@chromium.org812308e2012-02-29 15:58:45 +00003856 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003857 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003858
3859 RegExpImpl::IrregexpResult result =
3860 RegExpImpl::IrregexpExecOnce(regexp,
3861 subject,
3862 0,
3863 register_vector);
3864
3865 int capture_count = regexp->CaptureCount();
3866 int subject_length = subject->length();
3867
3868 // Position to search from.
3869 int pos = 0;
3870 // End of previous match. Differs from pos if match was empty.
3871 int match_end = 0;
3872 if (result == RegExpImpl::RE_SUCCESS) {
3873 // Need to keep a copy of the previous match for creating last_match_info
3874 // at the end, so we have two vectors that we swap between.
ulan@chromium.org812308e2012-02-29 15:58:45 +00003875 OffsetsVector registers2(required_registers, isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003876 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003877 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003878 do {
3879 int match_start = register_vector[0];
3880 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3881 if (match_end < match_start) {
3882 ReplacementStringBuilder::AddSubjectSlice(builder,
3883 match_end,
3884 match_start);
3885 }
3886 match_end = register_vector[1];
3887
3888 {
3889 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003890 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003891 // Arguments array to replace function is match, captures, index and
3892 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003893 Handle<FixedArray> elements =
3894 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003895 Handle<String> match;
3896 if (!first) {
3897 match = isolate->factory()->NewProperSubString(subject,
3898 match_start,
3899 match_end);
3900 } else {
3901 match = isolate->factory()->NewSubString(subject,
3902 match_start,
3903 match_end);
3904 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003905 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003906 for (int i = 1; i <= capture_count; i++) {
3907 int start = register_vector[i * 2];
3908 if (start >= 0) {
3909 int end = register_vector[i * 2 + 1];
3910 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003911 Handle<String> substring;
3912 if (!first) {
3913 substring = isolate->factory()->NewProperSubString(subject,
3914 start,
3915 end);
3916 } else {
3917 substring = isolate->factory()->NewSubString(subject, start, end);
3918 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003919 elements->set(i, *substring);
3920 } else {
3921 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003922 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003923 }
3924 }
3925 elements->set(capture_count + 1, Smi::FromInt(match_start));
3926 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003927 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003928 }
3929 // Swap register vectors, so the last successful match is in
3930 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003931 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003932 prev_register_vector = register_vector;
3933 register_vector = tmp;
3934
3935 if (match_end > match_start) {
3936 pos = match_end;
3937 } else {
3938 pos = match_end + 1;
3939 if (pos > subject_length) {
3940 break;
3941 }
3942 }
3943
3944 result = RegExpImpl::IrregexpExecOnce(regexp,
3945 subject,
3946 pos,
3947 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003948 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003949 } while (result == RegExpImpl::RE_SUCCESS);
3950
3951 if (result != RegExpImpl::RE_EXCEPTION) {
3952 // Finished matching, with at least one match.
3953 if (match_end < subject_length) {
3954 ReplacementStringBuilder::AddSubjectSlice(builder,
3955 match_end,
3956 subject_length);
3957 }
3958
3959 int last_match_capture_count = (capture_count + 1) * 2;
3960 int last_match_array_size =
3961 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3962 last_match_array->EnsureSize(last_match_array_size);
3963 AssertNoAllocation no_gc;
3964 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3965 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3966 RegExpImpl::SetLastSubject(elements, *subject);
3967 RegExpImpl::SetLastInput(elements, *subject);
3968 for (int i = 0; i < last_match_capture_count; i++) {
3969 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3970 }
3971 return RegExpImpl::RE_SUCCESS;
3972 }
3973 }
3974 // No matches at all, return failure or exception result directly.
3975 return result;
3976}
3977
3978
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003979RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003980 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003981 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003982
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003983 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003984 if (!subject->IsFlat()) FlattenString(subject);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003985 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
3986 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
3987 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003988
3989 ASSERT(last_match_info->HasFastElements());
3990 ASSERT(regexp->GetFlags().is_global());
3991 Handle<FixedArray> result_elements;
3992 if (result_array->HasFastElements()) {
3993 result_elements =
3994 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003995 }
3996 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003997 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003998 }
3999 FixedArrayBuilder builder(result_elements);
4000
4001 if (regexp->TypeTag() == JSRegExp::ATOM) {
4002 Handle<String> pattern(
4003 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004004 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004005 if (SearchStringMultiple(isolate, subject, pattern,
4006 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00004007 return *builder.ToJSArray(result_array);
4008 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004009 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004010 }
4011
4012 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
4013
4014 RegExpImpl::IrregexpResult result;
4015 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004016 result = SearchRegExpNoCaptureMultiple(isolate,
4017 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00004018 regexp,
4019 last_match_info,
4020 &builder);
4021 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004022 result = SearchRegExpMultiple(isolate,
4023 subject,
4024 regexp,
4025 last_match_info,
4026 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004027 }
4028 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004029 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004030 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4031 return Failure::Exception();
4032}
4033
4034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004035RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004036 NoHandleAllocation ha;
4037 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004038 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004039 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004040
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004041 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004042 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004043 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004044 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004045 // Character array used for conversion.
4046 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004047 return isolate->heap()->
4048 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004049 }
4050 }
4051
4052 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004053 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004055 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 }
4057 if (isinf(value)) {
4058 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004059 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004060 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004061 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004062 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004064 MaybeObject* result =
4065 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004066 DeleteArray(str);
4067 return result;
4068}
4069
4070
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004071RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 NoHandleAllocation ha;
4073 ASSERT(args.length() == 2);
4074
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004075 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004076 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004077 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004078 }
4079 if (isinf(value)) {
4080 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004081 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004083 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004085 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004086 int f = FastD2I(f_number);
4087 RUNTIME_ASSERT(f >= 0);
4088 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004089 MaybeObject* res =
4090 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004091 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004092 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004093}
4094
4095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004096RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004097 NoHandleAllocation ha;
4098 ASSERT(args.length() == 2);
4099
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004100 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004101 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004102 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004103 }
4104 if (isinf(value)) {
4105 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004106 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004108 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004110 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111 int f = FastD2I(f_number);
4112 RUNTIME_ASSERT(f >= -1 && f <= 20);
4113 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004114 MaybeObject* res =
4115 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004116 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004117 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118}
4119
4120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004121RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004122 NoHandleAllocation ha;
4123 ASSERT(args.length() == 2);
4124
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004125 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004127 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004128 }
4129 if (isinf(value)) {
4130 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004131 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004132 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004133 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004134 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004135 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004136 int f = FastD2I(f_number);
4137 RUNTIME_ASSERT(f >= 1 && f <= 21);
4138 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004139 MaybeObject* res =
4140 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004141 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004142 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143}
4144
4145
4146// Returns a single character string where first character equals
4147// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004148static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004149 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004150 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004151 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004152 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004153 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004154 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004155}
4156
4157
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004158MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4159 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004160 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004161 // Handle [] indexing on Strings
4162 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004163 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4164 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004165 }
4166
4167 // Handle [] indexing on String objects
4168 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004169 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4170 Handle<Object> result =
4171 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4172 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004173 }
4174
4175 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004176 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004177 }
4178
4179 return object->GetElement(index);
4180}
4181
4182
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004183MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4184 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004185 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004186 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004187
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004188 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004189 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004191 isolate->factory()->NewTypeError("non_object_property_load",
4192 HandleVector(args, 2));
4193 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194 }
4195
4196 // Check if the given key is an array index.
4197 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004198 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004199 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004200 }
4201
4202 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004203 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004204 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004205 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004206 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004207 bool has_pending_exception = false;
4208 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004209 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004210 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004211 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004212 }
4213
ager@chromium.org32912102009-01-16 10:38:43 +00004214 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004215 // the element if so.
4216 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004217 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004218 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004219 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004220 }
4221}
4222
4223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004224RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004225 NoHandleAllocation ha;
4226 ASSERT(args.length() == 2);
4227
4228 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004229 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004230
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004231 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232}
4233
4234
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004235// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004236RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004237 NoHandleAllocation ha;
4238 ASSERT(args.length() == 2);
4239
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004240 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004241 // itself.
4242 //
4243 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004244 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004245 // global proxy object never has properties. This is the case
4246 // because the global proxy object forwards everything to its hidden
4247 // prototype including local lookups.
4248 //
4249 // Additionally, we need to make sure that we do not cache results
4250 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004251 if (args[0]->IsJSObject()) {
4252 if (!args[0]->IsJSGlobalProxy() &&
4253 !args[0]->IsAccessCheckNeeded() &&
4254 args[1]->IsString()) {
4255 JSObject* receiver = JSObject::cast(args[0]);
4256 String* key = String::cast(args[1]);
4257 if (receiver->HasFastProperties()) {
4258 // Attempt to use lookup cache.
4259 Map* receiver_map = receiver->map();
4260 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4261 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4262 if (offset != -1) {
4263 Object* value = receiver->FastPropertyAt(offset);
4264 return value->IsTheHole()
4265 ? isolate->heap()->undefined_value()
4266 : value;
4267 }
4268 // Lookup cache miss. Perform lookup and update the cache if
4269 // appropriate.
4270 LookupResult result(isolate);
4271 receiver->LocalLookup(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004272 if (result.IsFound() && result.type() == FIELD) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004273 int offset = result.GetFieldIndex();
4274 keyed_lookup_cache->Update(receiver_map, key, offset);
4275 return receiver->FastPropertyAt(offset);
4276 }
4277 } else {
4278 // Attempt dictionary lookup.
4279 StringDictionary* dictionary = receiver->property_dictionary();
4280 int entry = dictionary->FindEntry(key);
4281 if ((entry != StringDictionary::kNotFound) &&
4282 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4283 Object* value = dictionary->ValueAt(entry);
4284 if (!receiver->IsGlobalObject()) return value;
4285 value = JSGlobalPropertyCell::cast(value)->value();
4286 if (!value->IsTheHole()) return value;
4287 // If value is the hole do the general lookup.
4288 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004289 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004290 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4291 // JSObject without a string key. If the key is a Smi, check for a
4292 // definite out-of-bounds access to elements, which is a strong indicator
4293 // that subsequent accesses will also call the runtime. Proactively
4294 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4295 // doubles for those future calls in the case that the elements would
4296 // become FAST_DOUBLE_ELEMENTS.
4297 Handle<JSObject> js_object(args.at<JSObject>(0));
4298 ElementsKind elements_kind = js_object->GetElementsKind();
4299 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4300 elements_kind == FAST_DOUBLE_ELEMENTS) {
4301 FixedArrayBase* elements = js_object->elements();
4302 if (args.at<Smi>(1)->value() >= elements->length()) {
4303 MaybeObject* maybe_object = TransitionElements(js_object,
4304 FAST_ELEMENTS,
4305 isolate);
4306 if (maybe_object->IsFailure()) return maybe_object;
4307 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004308 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004309 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004310 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4311 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004312 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004313 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004314 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004315 if (index >= 0 && index < str->length()) {
4316 Handle<Object> result = GetCharAt(str, index);
4317 return *result;
4318 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004319 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004320
4321 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004322 return Runtime::GetObjectProperty(isolate,
4323 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004324 args.at<Object>(1));
4325}
4326
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004327
4328static bool IsValidAccessor(Handle<Object> obj) {
4329 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
4330}
4331
4332
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004333// Implements part of 8.12.9 DefineOwnProperty.
4334// There are 3 cases that lead here:
4335// Step 4b - define a new accessor property.
4336// Steps 9c & 12 - replace an existing data property with an accessor property.
4337// Step 12 - update an existing accessor property with an accessor or generic
4338// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004339RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004340 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004341 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004342 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004343 RUNTIME_ASSERT(!obj->IsNull());
4344 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
4345 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
4346 RUNTIME_ASSERT(IsValidAccessor(getter));
4347 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
4348 RUNTIME_ASSERT(IsValidAccessor(setter));
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004349 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00004350 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004351 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004352
danno@chromium.org88aa0582012-03-23 15:11:57 +00004353 bool fast = obj->HasFastProperties();
4354 JSObject::DefineAccessor(obj, name, getter, setter, attr);
4355 if (fast) JSObject::TransformToFastProperties(obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004356 return isolate->heap()->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00004357}
4358
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004359// Implements part of 8.12.9 DefineOwnProperty.
4360// There are 3 cases that lead here:
4361// Step 4a - define a new data property.
4362// Steps 9b & 12 - replace an existing accessor property with a data property.
4363// Step 12 - update an existing data property with a data or generic
4364// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004365RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004366 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004367 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004368 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
4369 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004370 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004371 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
ager@chromium.org5c838252010-02-19 08:53:10 +00004372 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004373 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4374
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004375 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004376 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004377
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004378 // Special case for callback properties.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004379 if (result.IsFound() && result.type() == CALLBACKS) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004380 Object* callback = result.GetCallbackObject();
4381 // To be compatible with Safari we do not change the value on API objects
4382 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4383 // the value.
4384 if (callback->IsAccessorInfo()) {
4385 return isolate->heap()->undefined_value();
4386 }
4387 // Avoid redefining foreign callback as data property, just use the stored
4388 // setter to update the value instead.
4389 // TODO(mstarzinger): So far this only works if property attributes don't
4390 // change, this should be fixed once we cleanup the underlying code.
4391 if (callback->IsForeign() && result.GetAttributes() == attr) {
4392 return js_object->SetPropertyWithCallback(callback,
4393 *name,
4394 *obj_value,
4395 result.holder(),
4396 kStrictMode);
4397 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004398 }
4399
ager@chromium.org5c838252010-02-19 08:53:10 +00004400 // Take special care when attributes are different and there is already
4401 // a property. For simplicity we normalize the property which enables us
4402 // to not worry about changing the instance_descriptor and creating a new
4403 // map. The current version of SetObjectProperty does not handle attributes
4404 // correctly in the case where a property is a field and is reset with
4405 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004406 if (result.IsProperty() &&
4407 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004408 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004409 if (js_object->IsJSGlobalProxy()) {
4410 // Since the result is a property, the prototype will exist so
4411 // we don't have to check for null.
4412 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004413 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004414 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004415 // Use IgnoreAttributes version since a readonly property may be
4416 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004417 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4418 *obj_value,
4419 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004420 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004421
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004422 return Runtime::ForceSetObjectProperty(isolate,
4423 js_object,
4424 name,
4425 obj_value,
4426 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004427}
4428
4429
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004430MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4431 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004432 Handle<Object> key,
4433 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004434 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004435 StrictModeFlag strict_mode) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004436 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004437 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004439 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004440 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004441 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004442 isolate->factory()->NewTypeError("non_object_property_store",
4443 HandleVector(args, 2));
4444 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004445 }
4446
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004447 if (object->IsJSProxy()) {
4448 bool has_pending_exception = false;
4449 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4450 if (has_pending_exception) return Failure::Exception();
4451 return JSProxy::cast(*object)->SetProperty(
4452 String::cast(*name), *value, attr, strict_mode);
4453 }
4454
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004455 // If the object isn't a JavaScript object, we ignore the store.
4456 if (!object->IsJSObject()) return *value;
4457
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004458 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4459
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004460 // Check if the given key is an array index.
4461 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004462 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004463 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4464 // of a string using [] notation. We need to support this too in
4465 // JavaScript.
4466 // In the case of a String object we just need to redirect the assignment to
4467 // the underlying string if the index is in range. Since the underlying
4468 // string does nothing with the assignment then we can ignore such
4469 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004470 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004471 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004472 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004473
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004474 Handle<Object> result = JSObject::SetElement(
4475 js_object, index, value, attr, strict_mode, set_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004476 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004477 return *value;
4478 }
4479
4480 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004481 Handle<Object> result;
4482 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004483 result = JSObject::SetElement(
4484 js_object, index, value, attr, strict_mode, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004485 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004486 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004487 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004488 result = JSReceiver::SetProperty(
4489 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004490 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004491 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004492 return *value;
4493 }
4494
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004495 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004496 bool has_pending_exception = false;
4497 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4498 if (has_pending_exception) return Failure::Exception();
4499 Handle<String> name = Handle<String>::cast(converted);
4500
4501 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004502 return js_object->SetElement(
4503 index, *value, attr, strict_mode, true, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004504 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004505 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004506 }
4507}
4508
4509
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004510MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4511 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004512 Handle<Object> key,
4513 Handle<Object> value,
4514 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004515 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004516
4517 // Check if the given key is an array index.
4518 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004519 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004520 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4521 // of a string using [] notation. We need to support this too in
4522 // JavaScript.
4523 // In the case of a String object we just need to redirect the assignment to
4524 // the underlying string if the index is in range. Since the underlying
4525 // string does nothing with the assignment then we can ignore such
4526 // assignments.
4527 if (js_object->IsStringObjectWithCharacterAt(index)) {
4528 return *value;
4529 }
4530
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004531 return js_object->SetElement(
4532 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004533 }
4534
4535 if (key->IsString()) {
4536 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004537 return js_object->SetElement(
4538 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004539 } else {
4540 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004541 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004542 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4543 *value,
4544 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004545 }
4546 }
4547
4548 // Call-back into JavaScript to convert the key to a string.
4549 bool has_pending_exception = false;
4550 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4551 if (has_pending_exception) return Failure::Exception();
4552 Handle<String> name = Handle<String>::cast(converted);
4553
4554 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004555 return js_object->SetElement(
4556 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004557 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004558 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004559 }
4560}
4561
4562
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004563MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004564 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004565 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004566 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004567
4568 // Check if the given key is an array index.
4569 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004570 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004571 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4572 // characters of a string using [] notation. In the case of a
4573 // String object we just need to redirect the deletion to the
4574 // underlying string if the index is in range. Since the
4575 // underlying string does nothing with the deletion, we can ignore
4576 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004577 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004578 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004579 }
4580
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004581 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004582 }
4583
4584 Handle<String> key_string;
4585 if (key->IsString()) {
4586 key_string = Handle<String>::cast(key);
4587 } else {
4588 // Call-back into JavaScript to convert the key to a string.
4589 bool has_pending_exception = false;
4590 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4591 if (has_pending_exception) return Failure::Exception();
4592 key_string = Handle<String>::cast(converted);
4593 }
4594
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004595 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004596 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004597}
4598
4599
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004600RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004601 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004602 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603
4604 Handle<Object> object = args.at<Object>(0);
4605 Handle<Object> key = args.at<Object>(1);
4606 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004607 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004608 RUNTIME_ASSERT(
4609 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004610 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004611 PropertyAttributes attributes =
4612 static_cast<PropertyAttributes>(unchecked_attributes);
4613
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004614 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004615 if (args.length() == 5) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004616 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004617 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004618 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004619
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004620 return Runtime::SetObjectProperty(isolate,
4621 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004622 key,
4623 value,
4624 attributes,
4625 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004626}
4627
4628
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004629RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4630 NoHandleAllocation ha;
4631 RUNTIME_ASSERT(args.length() == 1);
4632 Handle<Object> object = args.at<Object>(0);
4633 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4634}
4635
4636
4637RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4638 NoHandleAllocation ha;
4639 RUNTIME_ASSERT(args.length() == 1);
4640 Handle<Object> object = args.at<Object>(0);
4641 return TransitionElements(object, FAST_ELEMENTS, isolate);
4642}
4643
4644
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004645// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004646// This is used to decide if we should transform null and undefined
4647// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004648RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004649 NoHandleAllocation ha;
4650 RUNTIME_ASSERT(args.length() == 1);
4651
4652 Handle<Object> object = args.at<Object>(0);
4653
4654 if (object->IsJSFunction()) {
4655 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004656 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004657 }
4658 return isolate->heap()->undefined_value();
4659}
4660
4661
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004662RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4663 RUNTIME_ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004664 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004665 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4666 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004667 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004668 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4669 HandleScope scope;
4670
4671 Object* raw_boilerplate_object = literals->get(literal_index);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004672 Handle<JSArray> boilerplate(JSArray::cast(raw_boilerplate_object));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004673#if DEBUG
4674 ElementsKind elements_kind = object->GetElementsKind();
4675#endif
4676 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4677 // Smis should never trigger transitions.
4678 ASSERT(!value->IsSmi());
4679
4680 if (value->IsNumber()) {
4681 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004682 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004683 if (IsMoreGeneralElementsKindTransition(boilerplate->GetElementsKind(),
4684 FAST_DOUBLE_ELEMENTS)) {
4685 JSObject::TransitionElementsKind(boilerplate, FAST_DOUBLE_ELEMENTS);
4686 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004687 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004688 FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004689 HeapNumber* number = HeapNumber::cast(*value);
4690 double_array->set(store_index, number->Number());
4691 } else {
4692 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4693 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004694 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004695 if (IsMoreGeneralElementsKindTransition(boilerplate->GetElementsKind(),
4696 FAST_ELEMENTS)) {
4697 JSObject::TransitionElementsKind(boilerplate, FAST_ELEMENTS);
4698 }
4699 FixedArray* object_array = FixedArray::cast(object->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004700 object_array->set(store_index, *value);
4701 }
4702 return *object;
4703}
4704
4705
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004706// Set a local property, even if it is READ_ONLY. If the property does not
4707// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004708RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004709 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004710 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004711 CONVERT_ARG_CHECKED(JSObject, object, 0);
4712 CONVERT_ARG_CHECKED(String, name, 1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004713 // Compute attributes.
4714 PropertyAttributes attributes = NONE;
4715 if (args.length() == 4) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004716 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004717 // Only attribute bits should be set.
4718 RUNTIME_ASSERT(
4719 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4720 attributes = static_cast<PropertyAttributes>(unchecked_value);
4721 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004722
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004723 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004724 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004725}
4726
4727
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004728RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004729 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004730 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004731
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004732 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4733 CONVERT_ARG_CHECKED(String, key, 1);
4734 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004735 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004736 ? JSReceiver::STRICT_DELETION
4737 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004738}
4739
4740
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004741static Object* HasLocalPropertyImplementation(Isolate* isolate,
4742 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004743 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004744 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004745 // Handle hidden prototypes. If there's a hidden prototype above this thing
4746 // then we have to check it for properties, because they are supposed to
4747 // look like they are on this object.
4748 Handle<Object> proto(object->GetPrototype());
4749 if (proto->IsJSObject() &&
4750 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004751 return HasLocalPropertyImplementation(isolate,
4752 Handle<JSObject>::cast(proto),
4753 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004754 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004755 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004756}
4757
4758
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004759RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004760 NoHandleAllocation ha;
4761 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004762 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004763
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004764 uint32_t index;
4765 const bool key_is_array_index = key->AsArrayIndex(&index);
4766
ager@chromium.org9085a012009-05-11 19:22:57 +00004767 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004768 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004769 if (obj->IsJSObject()) {
4770 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004771 // Fast case: either the key is a real named property or it is not
4772 // an array index and there are no interceptors or hidden
4773 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004774 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004775 Map* map = object->map();
4776 if (!key_is_array_index &&
4777 !map->has_named_interceptor() &&
4778 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4779 return isolate->heap()->false_value();
4780 }
4781 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004782 HandleScope scope(isolate);
4783 return HasLocalPropertyImplementation(isolate,
4784 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004785 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004786 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004787 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004788 String* string = String::cast(obj);
4789 if (index < static_cast<uint32_t>(string->length())) {
4790 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004791 }
4792 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004793 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004794}
4795
4796
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004797RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004798 NoHandleAllocation na;
4799 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004800 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4801 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004802
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004803 bool result = receiver->HasProperty(key);
4804 if (isolate->has_pending_exception()) return Failure::Exception();
4805 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004806}
4807
4808
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004809RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004810 NoHandleAllocation na;
4811 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004812 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4813 CONVERT_SMI_ARG_CHECKED(index, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004814
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004815 bool result = receiver->HasElement(index);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004816 if (isolate->has_pending_exception()) return Failure::Exception();
4817 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004818}
4819
4820
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004821RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004822 NoHandleAllocation ha;
4823 ASSERT(args.length() == 2);
4824
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004825 CONVERT_ARG_CHECKED(JSObject, object, 0);
4826 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004827
4828 uint32_t index;
4829 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004830 JSObject::LocalElementType type = object->HasLocalElement(index);
4831 switch (type) {
4832 case JSObject::UNDEFINED_ELEMENT:
4833 case JSObject::STRING_CHARACTER_ELEMENT:
4834 return isolate->heap()->false_value();
4835 case JSObject::INTERCEPTED_ELEMENT:
4836 case JSObject::FAST_ELEMENT:
4837 return isolate->heap()->true_value();
4838 case JSObject::DICTIONARY_ELEMENT: {
4839 if (object->IsJSGlobalProxy()) {
4840 Object* proto = object->GetPrototype();
4841 if (proto->IsNull()) {
4842 return isolate->heap()->false_value();
4843 }
4844 ASSERT(proto->IsJSGlobalObject());
4845 object = JSObject::cast(proto);
4846 }
4847 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004848 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004849 if (elements->map() ==
4850 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004851 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004852 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004853 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004854 }
4855 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004856 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004857 PropertyDetails details = dictionary->DetailsAt(entry);
4858 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4859 }
4860 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004861 }
4862
ager@chromium.org870a0b62008-11-04 11:43:05 +00004863 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004864 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004865}
4866
4867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004868RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004869 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004870 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004871 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004872 bool threw = false;
4873 Handle<JSArray> result = GetKeysFor(object, &threw);
4874 if (threw) return Failure::Exception();
4875 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004876}
4877
4878
4879// Returns either a FixedArray as Runtime_GetPropertyNames,
4880// or, if the given object has an enum cache that contains
4881// all enumerable properties of the object and its prototypes
4882// have none, the map of the object. This is used to speed up
4883// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004884RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004885 ASSERT(args.length() == 1);
4886
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004887 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004888
4889 if (raw_object->IsSimpleEnum()) return raw_object->map();
4890
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004891 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004892 Handle<JSReceiver> object(raw_object);
4893 bool threw = false;
4894 Handle<FixedArray> content =
4895 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4896 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004897
4898 // Test again, since cache may have been built by preceding call.
4899 if (object->IsSimpleEnum()) return object->map();
4900
4901 return *content;
4902}
4903
4904
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004905// Find the length of the prototype chain that is to to handled as one. If a
4906// prototype object is hidden it is to be viewed as part of the the object it
4907// is prototype for.
4908static int LocalPrototypeChainLength(JSObject* obj) {
4909 int count = 1;
4910 Object* proto = obj->GetPrototype();
4911 while (proto->IsJSObject() &&
4912 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4913 count++;
4914 proto = JSObject::cast(proto)->GetPrototype();
4915 }
4916 return count;
4917}
4918
4919
4920// Return the names of the local named properties.
4921// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004922RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004923 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004924 ASSERT(args.length() == 1);
4925 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004926 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004927 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004928 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004929
4930 // Skip the global proxy as it has no properties and always delegates to the
4931 // real global object.
4932 if (obj->IsJSGlobalProxy()) {
4933 // Only collect names if access is permitted.
4934 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004935 !isolate->MayNamedAccess(*obj,
4936 isolate->heap()->undefined_value(),
4937 v8::ACCESS_KEYS)) {
4938 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4939 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004940 }
4941 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4942 }
4943
4944 // Find the number of objects making up this.
4945 int length = LocalPrototypeChainLength(*obj);
4946
4947 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004948 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004949 int total_property_count = 0;
4950 Handle<JSObject> jsproto = obj;
4951 for (int i = 0; i < length; i++) {
4952 // Only collect names if access is permitted.
4953 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004954 !isolate->MayNamedAccess(*jsproto,
4955 isolate->heap()->undefined_value(),
4956 v8::ACCESS_KEYS)) {
4957 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4958 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004959 }
4960 int n;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004961 n = jsproto->NumberOfLocalProperties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004962 local_property_count[i] = n;
4963 total_property_count += n;
4964 if (i < length - 1) {
4965 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4966 }
4967 }
4968
4969 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004970 Handle<FixedArray> names =
4971 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004972
4973 // Get the property names.
4974 jsproto = obj;
4975 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004976 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004977 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004978 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4979 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004980 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004981 proto_with_hidden_properties++;
4982 }
4983 if (i < length - 1) {
4984 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4985 }
4986 }
4987
4988 // Filter out name of hidden propeties object.
4989 if (proto_with_hidden_properties > 0) {
4990 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004991 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004992 names->length() - proto_with_hidden_properties);
4993 int dest_pos = 0;
4994 for (int i = 0; i < total_property_count; i++) {
4995 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004996 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004997 continue;
4998 }
4999 names->set(dest_pos++, name);
5000 }
5001 }
5002
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005003 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005004}
5005
5006
5007// Return the names of the local indexed properties.
5008// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005009RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005010 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005011 ASSERT(args.length() == 1);
5012 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005013 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005014 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005015 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005016
5017 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005018 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005019 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005020 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005021}
5022
5023
5024// Return information on whether an object has a named or indexed interceptor.
5025// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005026RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005027 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005028 ASSERT(args.length() == 1);
5029 if (!args[0]->IsJSObject()) {
5030 return Smi::FromInt(0);
5031 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005032 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005033
5034 int result = 0;
5035 if (obj->HasNamedInterceptor()) result |= 2;
5036 if (obj->HasIndexedInterceptor()) result |= 1;
5037
5038 return Smi::FromInt(result);
5039}
5040
5041
5042// Return property names from named interceptor.
5043// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005044RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005045 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005046 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005047 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005048
5049 if (obj->HasNamedInterceptor()) {
5050 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5051 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5052 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005053 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005054}
5055
5056
5057// Return element names from indexed interceptor.
5058// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005059RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005060 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005061 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005062 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005063
5064 if (obj->HasIndexedInterceptor()) {
5065 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5066 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5067 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005068 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005069}
5070
5071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005072RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005073 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005074 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005075 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005076 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005077
5078 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005079 // Do access checks before going to the global object.
5080 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005081 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005082 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005083 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5084 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005085 }
5086
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005087 Handle<Object> proto(object->GetPrototype());
5088 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005089 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005090 object = Handle<JSObject>::cast(proto);
5091 }
5092
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005093 bool threw = false;
5094 Handle<FixedArray> contents =
5095 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5096 if (threw) return Failure::Exception();
5097
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005098 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5099 // property array and since the result is mutable we have to create
5100 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005101 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005102 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005103 for (int i = 0; i < length; i++) {
5104 Object* entry = contents->get(i);
5105 if (entry->IsString()) {
5106 copy->set(i, entry);
5107 } else {
5108 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005109 HandleScope scope(isolate);
5110 Handle<Object> entry_handle(entry, isolate);
5111 Handle<Object> entry_str =
5112 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005113 copy->set(i, *entry_str);
5114 }
5115 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005116 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005117}
5118
5119
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005120RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005121 NoHandleAllocation ha;
5122 ASSERT(args.length() == 1);
5123
5124 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005125 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005126 it.AdvanceToArgumentsFrame();
5127 JavaScriptFrame* frame = it.frame();
5128
5129 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005130 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005131
5132 // Try to convert the key to an index. If successful and within
5133 // index return the the argument from the frame.
5134 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005135 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005136 return frame->GetParameter(index);
5137 }
5138
5139 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005140 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005141 bool exception = false;
5142 Handle<Object> converted =
5143 Execution::ToString(args.at<Object>(0), &exception);
5144 if (exception) return Failure::Exception();
5145 Handle<String> key = Handle<String>::cast(converted);
5146
5147 // Try to convert the string key into an array index.
5148 if (key->AsArrayIndex(&index)) {
5149 if (index < n) {
5150 return frame->GetParameter(index);
5151 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005152 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005153 }
5154 }
5155
5156 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005157 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5158 if (key->Equals(isolate->heap()->callee_symbol())) {
5159 Object* function = frame->function();
5160 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005161 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005162 return isolate->Throw(*isolate->factory()->NewTypeError(
5163 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5164 }
5165 return function;
5166 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005167
5168 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005169 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005170}
5171
5172
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005173RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005174 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005175 Object* object = args[0];
5176 return (object->IsJSObject() && !object->IsGlobalObject())
5177 ? JSObject::cast(object)->TransformToFastProperties(0)
5178 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005179}
5180
5181
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005182RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005183 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005184 Object* obj = args[0];
5185 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5186 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5187 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005188}
5189
5190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005191RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005192 NoHandleAllocation ha;
5193 ASSERT(args.length() == 1);
5194
5195 return args[0]->ToBoolean();
5196}
5197
5198
5199// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5200// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005201RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005202 NoHandleAllocation ha;
5203
5204 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005205 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005206 HeapObject* heap_obj = HeapObject::cast(obj);
5207
5208 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005209 if (heap_obj->map()->is_undetectable()) {
5210 return isolate->heap()->undefined_symbol();
5211 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005212
5213 InstanceType instance_type = heap_obj->map()->instance_type();
5214 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005215 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005216 }
5217
5218 switch (instance_type) {
5219 case ODDBALL_TYPE:
5220 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005221 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005222 }
5223 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005224 return FLAG_harmony_typeof
5225 ? isolate->heap()->null_symbol()
5226 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005227 }
5228 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005229 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005230 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005231 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005232 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005233 default:
5234 // For any kind of object not handled above, the spec rule for
5235 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005236 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005237 }
5238}
5239
5240
lrn@chromium.org25156de2010-04-06 13:10:27 +00005241static bool AreDigits(const char*s, int from, int to) {
5242 for (int i = from; i < to; i++) {
5243 if (s[i] < '0' || s[i] > '9') return false;
5244 }
5245
5246 return true;
5247}
5248
5249
5250static int ParseDecimalInteger(const char*s, int from, int to) {
5251 ASSERT(to - from < 10); // Overflow is not possible.
5252 ASSERT(from < to);
5253 int d = s[from] - '0';
5254
5255 for (int i = from + 1; i < to; i++) {
5256 d = 10 * d + (s[i] - '0');
5257 }
5258
5259 return d;
5260}
5261
5262
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005263RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005264 NoHandleAllocation ha;
5265 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005266 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005267 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005268
5269 // Fast case: short integer or some sorts of junk values.
5270 int len = subject->length();
5271 if (subject->IsSeqAsciiString()) {
5272 if (len == 0) return Smi::FromInt(0);
5273
5274 char const* data = SeqAsciiString::cast(subject)->GetChars();
5275 bool minus = (data[0] == '-');
5276 int start_pos = (minus ? 1 : 0);
5277
5278 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005279 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005280 } else if (data[start_pos] > '9') {
5281 // Fast check for a junk value. A valid string may start from a
5282 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5283 // the 'I' character ('Infinity'). All of that have codes not greater than
5284 // '9' except 'I'.
5285 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005286 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005287 }
5288 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5289 // The maximal/minimal smi has 10 digits. If the string has less digits we
5290 // know it will fit into the smi-data type.
5291 int d = ParseDecimalInteger(data, start_pos, len);
5292 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005293 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005294 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005295 } else if (!subject->HasHashCode() &&
5296 len <= String::kMaxArrayIndexSize &&
5297 (len == 1 || data[0] != '0')) {
5298 // String hash is not calculated yet but all the data are present.
5299 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005300 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005301#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005302 subject->Hash(); // Force hash calculation.
5303 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5304 static_cast<int>(hash));
5305#endif
5306 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005307 }
5308 return Smi::FromInt(d);
5309 }
5310 }
5311
5312 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005313 return isolate->heap()->NumberFromDouble(
5314 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005315}
5316
5317
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005318RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005319 NoHandleAllocation ha;
5320 ASSERT(args.length() == 1);
5321
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005322 CONVERT_ARG_CHECKED(JSArray, codes, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005323 int length = Smi::cast(codes->length())->value();
5324
5325 // Check if the string can be ASCII.
5326 int i;
5327 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005328 Object* element;
5329 { MaybeObject* maybe_element = codes->GetElement(i);
5330 // We probably can't get an exception here, but just in order to enforce
5331 // the checking of inputs in the runtime calls we check here.
5332 if (!maybe_element->ToObject(&element)) return maybe_element;
5333 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005334 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5335 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5336 break;
5337 }
5338
lrn@chromium.org303ada72010-10-27 09:33:13 +00005339 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005340 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005341 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005342 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005343 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005344 }
5345
lrn@chromium.org303ada72010-10-27 09:33:13 +00005346 Object* object = NULL;
5347 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005348 String* result = String::cast(object);
5349 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005350 Object* element;
5351 { MaybeObject* maybe_element = codes->GetElement(i);
5352 if (!maybe_element->ToObject(&element)) return maybe_element;
5353 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005354 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005355 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005356 }
5357 return result;
5358}
5359
5360
5361// kNotEscaped is generated by the following:
5362//
5363// #!/bin/perl
5364// for (my $i = 0; $i < 256; $i++) {
5365// print "\n" if $i % 16 == 0;
5366// my $c = chr($i);
5367// my $escaped = 1;
5368// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5369// print $escaped ? "0, " : "1, ";
5370// }
5371
5372
5373static bool IsNotEscaped(uint16_t character) {
5374 // Only for 8 bit characters, the rest are always escaped (in a different way)
5375 ASSERT(character < 256);
5376 static const char kNotEscaped[256] = {
5377 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5378 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5379 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5380 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5381 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5382 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5383 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5384 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5385 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5386 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5387 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5388 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5389 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5390 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5391 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5392 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5393 };
5394 return kNotEscaped[character] != 0;
5395}
5396
5397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005398RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005399 const char hex_chars[] = "0123456789ABCDEF";
5400 NoHandleAllocation ha;
5401 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005402 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005403
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005404 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005405
5406 int escaped_length = 0;
5407 int length = source->length();
5408 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005409 Access<StringInputBuffer> buffer(
5410 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005411 buffer->Reset(source);
5412 while (buffer->has_more()) {
5413 uint16_t character = buffer->GetNext();
5414 if (character >= 256) {
5415 escaped_length += 6;
5416 } else if (IsNotEscaped(character)) {
5417 escaped_length++;
5418 } else {
5419 escaped_length += 3;
5420 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005421 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005422 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005423 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005424 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005425 return Failure::OutOfMemoryException();
5426 }
5427 }
5428 }
5429 // No length change implies no change. Return original string if no change.
5430 if (escaped_length == length) {
5431 return source;
5432 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005433 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005434 { MaybeObject* maybe_o =
5435 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005436 if (!maybe_o->ToObject(&o)) return maybe_o;
5437 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005438 String* destination = String::cast(o);
5439 int dest_position = 0;
5440
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005441 Access<StringInputBuffer> buffer(
5442 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005443 buffer->Rewind();
5444 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005445 uint16_t chr = buffer->GetNext();
5446 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005447 destination->Set(dest_position, '%');
5448 destination->Set(dest_position+1, 'u');
5449 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5450 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5451 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5452 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005453 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005454 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005455 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005456 dest_position++;
5457 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005458 destination->Set(dest_position, '%');
5459 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5460 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005461 dest_position += 3;
5462 }
5463 }
5464 return destination;
5465}
5466
5467
5468static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5469 static const signed char kHexValue['g'] = {
5470 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5471 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5472 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5473 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5474 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5475 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5476 -1, 10, 11, 12, 13, 14, 15 };
5477
5478 if (character1 > 'f') return -1;
5479 int hi = kHexValue[character1];
5480 if (hi == -1) return -1;
5481 if (character2 > 'f') return -1;
5482 int lo = kHexValue[character2];
5483 if (lo == -1) return -1;
5484 return (hi << 4) + lo;
5485}
5486
5487
ager@chromium.org870a0b62008-11-04 11:43:05 +00005488static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005489 int i,
5490 int length,
5491 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005492 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005493 int32_t hi = 0;
5494 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005495 if (character == '%' &&
5496 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005497 source->Get(i + 1) == 'u' &&
5498 (hi = TwoDigitHex(source->Get(i + 2),
5499 source->Get(i + 3))) != -1 &&
5500 (lo = TwoDigitHex(source->Get(i + 4),
5501 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005502 *step = 6;
5503 return (hi << 8) + lo;
5504 } else if (character == '%' &&
5505 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005506 (lo = TwoDigitHex(source->Get(i + 1),
5507 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005508 *step = 3;
5509 return lo;
5510 } else {
5511 *step = 1;
5512 return character;
5513 }
5514}
5515
5516
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005517RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005518 NoHandleAllocation ha;
5519 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005520 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005521
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005522 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005523
5524 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005525 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005526
5527 int unescaped_length = 0;
5528 for (int i = 0; i < length; unescaped_length++) {
5529 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005530 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005531 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005532 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005533 i += step;
5534 }
5535
5536 // No length change implies no change. Return original string if no change.
5537 if (unescaped_length == length)
5538 return source;
5539
lrn@chromium.org303ada72010-10-27 09:33:13 +00005540 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005541 { MaybeObject* maybe_o =
5542 ascii ?
5543 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5544 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005545 if (!maybe_o->ToObject(&o)) return maybe_o;
5546 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005547 String* destination = String::cast(o);
5548
5549 int dest_position = 0;
5550 for (int i = 0; i < length; dest_position++) {
5551 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005552 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005553 i += step;
5554 }
5555 return destination;
5556}
5557
5558
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005559static const unsigned int kQuoteTableLength = 128u;
5560
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005561static const int kJsonQuotesCharactersPerEntry = 8;
5562static const char* const JsonQuotes =
5563 "\\u0000 \\u0001 \\u0002 \\u0003 "
5564 "\\u0004 \\u0005 \\u0006 \\u0007 "
5565 "\\b \\t \\n \\u000b "
5566 "\\f \\r \\u000e \\u000f "
5567 "\\u0010 \\u0011 \\u0012 \\u0013 "
5568 "\\u0014 \\u0015 \\u0016 \\u0017 "
5569 "\\u0018 \\u0019 \\u001a \\u001b "
5570 "\\u001c \\u001d \\u001e \\u001f "
5571 " ! \\\" # "
5572 "$ % & ' "
5573 "( ) * + "
5574 ", - . / "
5575 "0 1 2 3 "
5576 "4 5 6 7 "
5577 "8 9 : ; "
5578 "< = > ? "
5579 "@ A B C "
5580 "D E F G "
5581 "H I J K "
5582 "L M N O "
5583 "P Q R S "
5584 "T U V W "
5585 "X Y Z [ "
5586 "\\\\ ] ^ _ "
5587 "` a b c "
5588 "d e f g "
5589 "h i j k "
5590 "l m n o "
5591 "p q r s "
5592 "t u v w "
5593 "x y z { "
5594 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005595
5596
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005597// For a string that is less than 32k characters it should always be
5598// possible to allocate it in new space.
5599static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5600
5601
5602// Doing JSON quoting cannot make the string more than this many times larger.
5603static const int kJsonQuoteWorstCaseBlowup = 6;
5604
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005605static const int kSpaceForQuotesAndComma = 3;
5606static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005607
5608// Covers the entire ASCII range (all other characters are unchanged by JSON
5609// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005610static const byte JsonQuoteLengths[kQuoteTableLength] = {
5611 6, 6, 6, 6, 6, 6, 6, 6,
5612 2, 2, 2, 6, 2, 2, 6, 6,
5613 6, 6, 6, 6, 6, 6, 6, 6,
5614 6, 6, 6, 6, 6, 6, 6, 6,
5615 1, 1, 2, 1, 1, 1, 1, 1,
5616 1, 1, 1, 1, 1, 1, 1, 1,
5617 1, 1, 1, 1, 1, 1, 1, 1,
5618 1, 1, 1, 1, 1, 1, 1, 1,
5619 1, 1, 1, 1, 1, 1, 1, 1,
5620 1, 1, 1, 1, 1, 1, 1, 1,
5621 1, 1, 1, 1, 1, 1, 1, 1,
5622 1, 1, 1, 1, 2, 1, 1, 1,
5623 1, 1, 1, 1, 1, 1, 1, 1,
5624 1, 1, 1, 1, 1, 1, 1, 1,
5625 1, 1, 1, 1, 1, 1, 1, 1,
5626 1, 1, 1, 1, 1, 1, 1, 1,
5627};
5628
5629
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005630template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005631MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005632
5633
5634template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005635MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5636 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005637}
5638
5639
5640template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005641MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5642 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005643}
5644
5645
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005646template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005647static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5648 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005649 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005650 const Char* read_cursor = characters.start();
5651 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005652 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005653 int quoted_length = kSpaceForQuotes;
5654 while (read_cursor < end) {
5655 Char c = *(read_cursor++);
5656 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5657 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005658 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005659 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005660 }
5661 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005662 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5663 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005664 Object* new_object;
5665 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005666 return new_alloc;
5667 }
5668 StringType* new_string = StringType::cast(new_object);
5669
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005670 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005671 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005672 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005673 *(write_cursor++) = '"';
5674
5675 read_cursor = characters.start();
5676 while (read_cursor < end) {
5677 Char c = *(read_cursor++);
5678 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5679 *(write_cursor++) = c;
5680 } else {
5681 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5682 const char* replacement = JsonQuotes +
5683 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5684 for (int i = 0; i < len; i++) {
5685 *write_cursor++ = *replacement++;
5686 }
5687 }
5688 }
5689 *(write_cursor++) = '"';
5690 return new_string;
5691}
5692
5693
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005694template <typename SinkChar, typename SourceChar>
5695static inline SinkChar* WriteQuoteJsonString(
5696 Isolate* isolate,
5697 SinkChar* write_cursor,
5698 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005699 // SinkChar is only char if SourceChar is guaranteed to be char.
5700 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005701 const SourceChar* read_cursor = characters.start();
5702 const SourceChar* end = read_cursor + characters.length();
5703 *(write_cursor++) = '"';
5704 while (read_cursor < end) {
5705 SourceChar c = *(read_cursor++);
5706 if (sizeof(SourceChar) > 1u &&
5707 static_cast<unsigned>(c) >= kQuoteTableLength) {
5708 *(write_cursor++) = static_cast<SinkChar>(c);
5709 } else {
5710 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5711 const char* replacement = JsonQuotes +
5712 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5713 write_cursor[0] = replacement[0];
5714 if (len > 1) {
5715 write_cursor[1] = replacement[1];
5716 if (len > 2) {
5717 ASSERT(len == 6);
5718 write_cursor[2] = replacement[2];
5719 write_cursor[3] = replacement[3];
5720 write_cursor[4] = replacement[4];
5721 write_cursor[5] = replacement[5];
5722 }
5723 }
5724 write_cursor += len;
5725 }
5726 }
5727 *(write_cursor++) = '"';
5728 return write_cursor;
5729}
5730
5731
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005732template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005733static MaybeObject* QuoteJsonString(Isolate* isolate,
5734 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005735 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005736 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005737 int worst_case_length =
5738 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005739 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005740 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005741 }
5742
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005743 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5744 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005745 Object* new_object;
5746 if (!new_alloc->ToObject(&new_object)) {
5747 return new_alloc;
5748 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005749 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005750 // Even if our string is small enough to fit in new space we still have to
5751 // handle it being allocated in old space as may happen in the third
5752 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5753 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005754 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005755 }
5756 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005757 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005758
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005759 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005760 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005761 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005762 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5763 write_cursor,
5764 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005765 int final_length = static_cast<int>(
5766 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005767 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005768 isolate->heap()->new_space()->
5769 template ShrinkStringAtAllocationBoundary<StringType>(
5770 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005771 return new_string;
5772}
5773
5774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005775RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005776 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005777 CONVERT_ARG_CHECKED(String, str, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005778 if (!str->IsFlat()) {
5779 MaybeObject* try_flatten = str->TryFlatten();
5780 Object* flat;
5781 if (!try_flatten->ToObject(&flat)) {
5782 return try_flatten;
5783 }
5784 str = String::cast(flat);
5785 ASSERT(str->IsFlat());
5786 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005787 String::FlatContent flat = str->GetFlatContent();
5788 ASSERT(flat.IsFlat());
5789 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005790 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005791 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005792 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005793 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005794 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005795 }
5796}
5797
5798
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005799RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005800 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005801 CONVERT_ARG_CHECKED(String, str, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005802 if (!str->IsFlat()) {
5803 MaybeObject* try_flatten = str->TryFlatten();
5804 Object* flat;
5805 if (!try_flatten->ToObject(&flat)) {
5806 return try_flatten;
5807 }
5808 str = String::cast(flat);
5809 ASSERT(str->IsFlat());
5810 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005811 String::FlatContent flat = str->GetFlatContent();
5812 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005813 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005814 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005815 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005816 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005817 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005818 }
5819}
5820
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005821
5822template <typename Char, typename StringType>
5823static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5824 FixedArray* array,
5825 int worst_case_length) {
5826 int length = array->length();
5827
5828 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5829 worst_case_length);
5830 Object* new_object;
5831 if (!new_alloc->ToObject(&new_object)) {
5832 return new_alloc;
5833 }
5834 if (!isolate->heap()->new_space()->Contains(new_object)) {
5835 // Even if our string is small enough to fit in new space we still have to
5836 // handle it being allocated in old space as may happen in the third
5837 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5838 // CEntryStub::GenerateCore.
5839 return isolate->heap()->undefined_value();
5840 }
5841 AssertNoAllocation no_gc;
5842 StringType* new_string = StringType::cast(new_object);
5843 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5844
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005845 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005846 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005847 *(write_cursor++) = '[';
5848 for (int i = 0; i < length; i++) {
5849 if (i != 0) *(write_cursor++) = ',';
5850 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005851 String::FlatContent content = str->GetFlatContent();
5852 ASSERT(content.IsFlat());
5853 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005854 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5855 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005856 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005857 } else {
5858 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5859 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005860 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005861 }
5862 }
5863 *(write_cursor++) = ']';
5864
5865 int final_length = static_cast<int>(
5866 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005867 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005868 isolate->heap()->new_space()->
5869 template ShrinkStringAtAllocationBoundary<StringType>(
5870 new_string, final_length);
5871 return new_string;
5872}
5873
5874
5875RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5876 NoHandleAllocation ha;
5877 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005878 CONVERT_ARG_CHECKED(JSArray, array, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005879
5880 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5881 FixedArray* elements = FixedArray::cast(array->elements());
5882 int n = elements->length();
5883 bool ascii = true;
5884 int total_length = 0;
5885
5886 for (int i = 0; i < n; i++) {
5887 Object* elt = elements->get(i);
5888 if (!elt->IsString()) return isolate->heap()->undefined_value();
5889 String* element = String::cast(elt);
5890 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5891 total_length += element->length();
5892 if (ascii && element->IsTwoByteRepresentation()) {
5893 ascii = false;
5894 }
5895 }
5896
5897 int worst_case_length =
5898 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5899 + total_length * kJsonQuoteWorstCaseBlowup;
5900
5901 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5902 return isolate->heap()->undefined_value();
5903 }
5904
5905 if (ascii) {
5906 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5907 elements,
5908 worst_case_length);
5909 } else {
5910 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5911 elements,
5912 worst_case_length);
5913 }
5914}
5915
5916
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005917RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918 NoHandleAllocation ha;
5919
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005920 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005921 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005922
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005923 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005924
lrn@chromium.org25156de2010-04-06 13:10:27 +00005925 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005926 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005927 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005928}
5929
5930
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005931RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005932 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005933 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005934
5935 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005936 double value = StringToDouble(isolate->unicode_cache(),
5937 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005938
5939 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005940 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005941}
5942
5943
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005944template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005945MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005946 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005947 String* s,
5948 int length,
5949 int input_string_length,
5950 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005951 // We try this twice, once with the assumption that the result is no longer
5952 // than the input and, if that assumption breaks, again with the exact
5953 // length. This may not be pretty, but it is nicer than what was here before
5954 // and I hereby claim my vaffel-is.
5955 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005956 // Allocate the resulting string.
5957 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005958 // NOTE: This assumes that the upper/lower case of an ASCII
5959 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005960 // might break in the future if we implement more context and locale
5961 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005962 Object* o;
5963 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005964 ? isolate->heap()->AllocateRawAsciiString(length)
5965 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005966 if (!maybe_o->ToObject(&o)) return maybe_o;
5967 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005968 String* result = String::cast(o);
5969 bool has_changed_character = false;
5970
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005971 // Convert all characters to upper case, assuming that they will fit
5972 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005973 Access<StringInputBuffer> buffer(
5974 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005975 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005976 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005977 // We can assume that the string is not empty
5978 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005979 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005980 bool has_next = buffer->has_more();
5981 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982 int char_length = mapping->get(current, next, chars);
5983 if (char_length == 0) {
5984 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005985 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005986 i++;
5987 } else if (char_length == 1) {
5988 // Common case: converting the letter resulted in one character.
5989 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005990 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005991 has_changed_character = true;
5992 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005993 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005994 // We've assumed that the result would be as long as the
5995 // input but here is a character that converts to several
5996 // characters. No matter, we calculate the exact length
5997 // of the result and try the whole thing again.
5998 //
5999 // Note that this leaves room for optimization. We could just
6000 // memcpy what we already have to the result string. Also,
6001 // the result string is the last object allocated we could
6002 // "realloc" it and probably, in the vast majority of cases,
6003 // extend the existing string to be able to hold the full
6004 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006005 int next_length = 0;
6006 if (has_next) {
6007 next_length = mapping->get(next, 0, chars);
6008 if (next_length == 0) next_length = 1;
6009 }
6010 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006011 while (buffer->has_more()) {
6012 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006013 // NOTE: we use 0 as the next character here because, while
6014 // the next character may affect what a character converts to,
6015 // it does not in any case affect the length of what it convert
6016 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006017 int char_length = mapping->get(current, 0, chars);
6018 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006019 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006020 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006021 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006022 return Failure::OutOfMemoryException();
6023 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006024 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006025 // Try again with the real length.
6026 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006027 } else {
6028 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006029 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006030 i++;
6031 }
6032 has_changed_character = true;
6033 }
6034 current = next;
6035 }
6036 if (has_changed_character) {
6037 return result;
6038 } else {
6039 // If we didn't actually change anything in doing the conversion
6040 // we simple return the result and let the converted string
6041 // become garbage; there is no reason to keep two identical strings
6042 // alive.
6043 return s;
6044 }
6045}
6046
6047
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006048namespace {
6049
lrn@chromium.org303ada72010-10-27 09:33:13 +00006050static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6051
6052
6053// Given a word and two range boundaries returns a word with high bit
6054// set in every byte iff the corresponding input byte was strictly in
6055// the range (m, n). All the other bits in the result are cleared.
6056// This function is only useful when it can be inlined and the
6057// boundaries are statically known.
6058// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006059// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006060static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006061 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006062 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6063 // Use strict inequalities since in edge cases the function could be
6064 // further simplified.
6065 ASSERT(0 < m && m < n && n < 0x7F);
6066 // Has high bit set in every w byte less than n.
6067 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6068 // Has high bit set in every w byte greater than m.
6069 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6070 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6071}
6072
6073
6074enum AsciiCaseConversion {
6075 ASCII_TO_LOWER,
6076 ASCII_TO_UPPER
6077};
6078
6079
6080template <AsciiCaseConversion dir>
6081struct FastAsciiConverter {
6082 static bool Convert(char* dst, char* src, int length) {
6083#ifdef DEBUG
6084 char* saved_dst = dst;
6085 char* saved_src = src;
6086#endif
6087 // We rely on the distance between upper and lower case letters
6088 // being a known power of 2.
6089 ASSERT('a' - 'A' == (1 << 5));
6090 // Boundaries for the range of input characters than require conversion.
6091 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6092 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6093 bool changed = false;
6094 char* const limit = src + length;
6095#ifdef V8_HOST_CAN_READ_UNALIGNED
6096 // Process the prefix of the input that requires no conversion one
6097 // (machine) word at a time.
6098 while (src <= limit - sizeof(uintptr_t)) {
6099 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6100 if (AsciiRangeMask(w, lo, hi) != 0) {
6101 changed = true;
6102 break;
6103 }
6104 *reinterpret_cast<uintptr_t*>(dst) = w;
6105 src += sizeof(uintptr_t);
6106 dst += sizeof(uintptr_t);
6107 }
6108 // Process the remainder of the input performing conversion when
6109 // required one word at a time.
6110 while (src <= limit - sizeof(uintptr_t)) {
6111 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6112 uintptr_t m = AsciiRangeMask(w, lo, hi);
6113 // The mask has high (7th) bit set in every byte that needs
6114 // conversion and we know that the distance between cases is
6115 // 1 << 5.
6116 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6117 src += sizeof(uintptr_t);
6118 dst += sizeof(uintptr_t);
6119 }
6120#endif
6121 // Process the last few bytes of the input (or the whole input if
6122 // unaligned access is not supported).
6123 while (src < limit) {
6124 char c = *src;
6125 if (lo < c && c < hi) {
6126 c ^= (1 << 5);
6127 changed = true;
6128 }
6129 *dst = c;
6130 ++src;
6131 ++dst;
6132 }
6133#ifdef DEBUG
6134 CheckConvert(saved_dst, saved_src, length, changed);
6135#endif
6136 return changed;
6137 }
6138
6139#ifdef DEBUG
6140 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6141 bool expected_changed = false;
6142 for (int i = 0; i < length; i++) {
6143 if (dst[i] == src[i]) continue;
6144 expected_changed = true;
6145 if (dir == ASCII_TO_LOWER) {
6146 ASSERT('A' <= src[i] && src[i] <= 'Z');
6147 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6148 } else {
6149 ASSERT(dir == ASCII_TO_UPPER);
6150 ASSERT('a' <= src[i] && src[i] <= 'z');
6151 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6152 }
6153 }
6154 ASSERT(expected_changed == changed);
6155 }
6156#endif
6157};
6158
6159
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006160struct ToLowerTraits {
6161 typedef unibrow::ToLowercase UnibrowConverter;
6162
lrn@chromium.org303ada72010-10-27 09:33:13 +00006163 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006164};
6165
6166
6167struct ToUpperTraits {
6168 typedef unibrow::ToUppercase UnibrowConverter;
6169
lrn@chromium.org303ada72010-10-27 09:33:13 +00006170 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006171};
6172
6173} // namespace
6174
6175
6176template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006177MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006178 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006179 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006180 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006181 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006182 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006183 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006184
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006185 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006186 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006187 if (length == 0) return s;
6188
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006189 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006190 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006191 // NOTE: This assumes that the upper/lower case of an ASCII
6192 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006193 // might break in the future if we implement more context and locale
6194 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006195 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006196 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006197 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006198 if (!maybe_o->ToObject(&o)) return maybe_o;
6199 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006200 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006201 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006202 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006203 return has_changed_character ? result : s;
6204 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006205
lrn@chromium.org303ada72010-10-27 09:33:13 +00006206 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006207 { MaybeObject* maybe_answer =
6208 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006209 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6210 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006211 if (answer->IsSmi()) {
6212 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006213 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006214 ConvertCaseHelper(isolate,
6215 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006216 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6217 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006218 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006219 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006220}
6221
6222
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006223RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006224 return ConvertCase<ToLowerTraits>(
6225 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006226}
6227
6228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006229RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006230 return ConvertCase<ToUpperTraits>(
6231 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006232}
6233
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006234
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006235static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006236 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006237}
6238
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006240RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006241 NoHandleAllocation ha;
6242 ASSERT(args.length() == 3);
6243
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006244 CONVERT_ARG_CHECKED(String, s, 0);
6245 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6246 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006247
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006248 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006249 int length = s->length();
6250
6251 int left = 0;
6252 if (trimLeft) {
6253 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6254 left++;
6255 }
6256 }
6257
6258 int right = length;
6259 if (trimRight) {
6260 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6261 right--;
6262 }
6263 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006264 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006265}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006266
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006267
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006268RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006269 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006270 HandleScope handle_scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006271 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6272 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006273 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6274
6275 int subject_length = subject->length();
6276 int pattern_length = pattern->length();
6277 RUNTIME_ASSERT(pattern_length > 0);
6278
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006279 if (limit == 0xffffffffu) {
6280 Handle<Object> cached_answer(StringSplitCache::Lookup(
6281 isolate->heap()->string_split_cache(),
6282 *subject,
6283 *pattern));
6284 if (*cached_answer != Smi::FromInt(0)) {
6285 Handle<JSArray> result =
6286 isolate->factory()->NewJSArrayWithElements(
6287 Handle<FixedArray>::cast(cached_answer));
6288 return *result;
6289 }
6290 }
6291
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006292 // The limit can be very large (0xffffffffu), but since the pattern
6293 // isn't empty, we can never create more parts than ~half the length
6294 // of the subject.
6295
6296 if (!subject->IsFlat()) FlattenString(subject);
6297
6298 static const int kMaxInitialListCapacity = 16;
6299
danno@chromium.org40cb8782011-05-25 07:58:50 +00006300 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006301
6302 // Find (up to limit) indices of separator and end-of-string in subject
6303 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6304 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006305 if (!pattern->IsFlat()) FlattenString(pattern);
6306
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006307 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006308
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006309 if (static_cast<uint32_t>(indices.length()) < limit) {
6310 indices.Add(subject_length);
6311 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006312
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006313 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006314
6315 // Create JSArray of substrings separated by separator.
6316 int part_count = indices.length();
6317
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006318 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006319 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006320 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006321 result->set_length(Smi::FromInt(part_count));
6322
6323 ASSERT(result->HasFastElements());
6324
6325 if (part_count == 1 && indices.at(0) == subject_length) {
6326 FixedArray::cast(result->elements())->set(0, *subject);
6327 return *result;
6328 }
6329
6330 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6331 int part_start = 0;
6332 for (int i = 0; i < part_count; i++) {
6333 HandleScope local_loop_handle;
6334 int part_end = indices.at(i);
6335 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006336 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006337 elements->set(i, *substring);
6338 part_start = part_end + pattern_length;
6339 }
6340
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006341 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006342 if (result->HasFastElements()) {
6343 StringSplitCache::Enter(isolate->heap(),
6344 isolate->heap()->string_split_cache(),
6345 *subject,
6346 *pattern,
6347 *elements);
6348 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006349 }
6350
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006351 return *result;
6352}
6353
6354
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006355// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006356// one-char strings in the cache. Gives up on the first char that is
6357// not in the cache and fills the remainder with smi zeros. Returns
6358// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006359static int CopyCachedAsciiCharsToArray(Heap* heap,
6360 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006361 FixedArray* elements,
6362 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006363 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006364 FixedArray* ascii_cache = heap->single_character_string_cache();
6365 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006366 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006367 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006368 for (i = 0; i < length; ++i) {
6369 Object* value = ascii_cache->get(chars[i]);
6370 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006371 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006372 }
6373 if (i < length) {
6374 ASSERT(Smi::FromInt(0) == 0);
6375 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6376 }
6377#ifdef DEBUG
6378 for (int j = 0; j < length; ++j) {
6379 Object* element = elements->get(j);
6380 ASSERT(element == Smi::FromInt(0) ||
6381 (element->IsString() && String::cast(element)->LooksValid()));
6382 }
6383#endif
6384 return i;
6385}
6386
6387
6388// Converts a String to JSArray.
6389// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006390RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006391 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006392 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006393 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006394 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006395
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006396 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006397 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006398
6399 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006400 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006401 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006402 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006403 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006404 { MaybeObject* maybe_obj =
6405 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006406 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6407 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006408 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006409 String::FlatContent content = s->GetFlatContent();
6410 if (content.IsAscii()) {
6411 Vector<const char> chars = content.ToAsciiVector();
6412 // Note, this will initialize all elements (not only the prefix)
6413 // to prevent GC from seeing partially initialized array.
6414 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6415 chars.start(),
6416 *elements,
6417 length);
6418 } else {
6419 MemsetPointer(elements->data_start(),
6420 isolate->heap()->undefined_value(),
6421 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006422 }
6423 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006424 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006425 }
6426 for (int i = position; i < length; ++i) {
6427 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6428 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006429 }
6430
6431#ifdef DEBUG
6432 for (int i = 0; i < length; ++i) {
6433 ASSERT(String::cast(elements->get(i))->length() == 1);
6434 }
6435#endif
6436
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006437 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006438}
6439
6440
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006441RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006442 NoHandleAllocation ha;
6443 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006444 CONVERT_ARG_CHECKED(String, value, 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006445 return value->ToObject();
6446}
6447
6448
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006449bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006450 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006451 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006452 return char_length == 0;
6453}
6454
6455
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006456RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006457 NoHandleAllocation ha;
6458 ASSERT(args.length() == 1);
6459
6460 Object* number = args[0];
6461 RUNTIME_ASSERT(number->IsNumber());
6462
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006463 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006464}
6465
6466
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006467RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006468 NoHandleAllocation ha;
6469 ASSERT(args.length() == 1);
6470
6471 Object* number = args[0];
6472 RUNTIME_ASSERT(number->IsNumber());
6473
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006474 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006475}
6476
6477
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006478RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006479 NoHandleAllocation ha;
6480 ASSERT(args.length() == 1);
6481
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006482 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006483
6484 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6485 if (number > 0 && number <= Smi::kMaxValue) {
6486 return Smi::FromInt(static_cast<int>(number));
6487 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006488 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006489}
6490
6491
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006492RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006493 NoHandleAllocation ha;
6494 ASSERT(args.length() == 1);
6495
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006496 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006497
6498 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6499 if (number > 0 && number <= Smi::kMaxValue) {
6500 return Smi::FromInt(static_cast<int>(number));
6501 }
6502
6503 double double_value = DoubleToInteger(number);
6504 // Map both -0 and +0 to +0.
6505 if (double_value == 0) double_value = 0;
6506
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006507 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006508}
6509
6510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006511RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006512 NoHandleAllocation ha;
6513 ASSERT(args.length() == 1);
6514
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006515 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006516 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006517}
6518
6519
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006520RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006521 NoHandleAllocation ha;
6522 ASSERT(args.length() == 1);
6523
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006524 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006525
6526 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6527 if (number > 0 && number <= Smi::kMaxValue) {
6528 return Smi::FromInt(static_cast<int>(number));
6529 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006530 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006531}
6532
6533
ager@chromium.org870a0b62008-11-04 11:43:05 +00006534// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6535// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006536RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006537 NoHandleAllocation ha;
6538 ASSERT(args.length() == 1);
6539
6540 Object* obj = args[0];
6541 if (obj->IsSmi()) {
6542 return obj;
6543 }
6544 if (obj->IsHeapNumber()) {
6545 double value = HeapNumber::cast(obj)->value();
6546 int int_value = FastD2I(value);
6547 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6548 return Smi::FromInt(int_value);
6549 }
6550 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006551 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006552}
6553
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006554
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006555RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006556 NoHandleAllocation ha;
6557 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006558 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006559}
6560
6561
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006562RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006563 NoHandleAllocation ha;
6564 ASSERT(args.length() == 2);
6565
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006566 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6567 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006568 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006569}
6570
6571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006572RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006573 NoHandleAllocation ha;
6574 ASSERT(args.length() == 2);
6575
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006576 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6577 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006578 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006579}
6580
6581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006582RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006583 NoHandleAllocation ha;
6584 ASSERT(args.length() == 2);
6585
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006586 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6587 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006588 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006589}
6590
6591
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006592RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006593 NoHandleAllocation ha;
6594 ASSERT(args.length() == 1);
6595
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006596 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006597 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006598}
6599
6600
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006601RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006602 NoHandleAllocation ha;
6603 ASSERT(args.length() == 0);
6604
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006605 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006606}
6607
6608
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006609RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006610 NoHandleAllocation ha;
6611 ASSERT(args.length() == 2);
6612
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006613 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6614 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006615 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006616}
6617
6618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006619RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006620 NoHandleAllocation ha;
6621 ASSERT(args.length() == 2);
6622
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006623 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6624 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006625
ager@chromium.org3811b432009-10-28 14:53:37 +00006626 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006627 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006628 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629}
6630
6631
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006632RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633 NoHandleAllocation ha;
6634 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006635 CONVERT_ARG_CHECKED(String, str1, 0);
6636 CONVERT_ARG_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006637 isolate->counters()->string_add_runtime()->Increment();
6638 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006639}
6640
6641
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006642template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006643static inline void StringBuilderConcatHelper(String* special,
6644 sinkchar* sink,
6645 FixedArray* fixed_array,
6646 int array_length) {
6647 int position = 0;
6648 for (int i = 0; i < array_length; i++) {
6649 Object* element = fixed_array->get(i);
6650 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006651 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006652 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006653 int pos;
6654 int len;
6655 if (encoded_slice > 0) {
6656 // Position and length encoded in one smi.
6657 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6658 len = StringBuilderSubstringLength::decode(encoded_slice);
6659 } else {
6660 // Position and length encoded in two smis.
6661 Object* obj = fixed_array->get(++i);
6662 ASSERT(obj->IsSmi());
6663 pos = Smi::cast(obj)->value();
6664 len = -encoded_slice;
6665 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006666 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006667 sink + position,
6668 pos,
6669 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006670 position += len;
6671 } else {
6672 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006673 int element_length = string->length();
6674 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006675 position += element_length;
6676 }
6677 }
6678}
6679
6680
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006681RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006682 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006683 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006684 CONVERT_ARG_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006685 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006686 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006687 return Failure::OutOfMemoryException();
6688 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006689 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006690 CONVERT_ARG_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006691
6692 // This assumption is used by the slice encoding in one or two smis.
6693 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6694
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006695 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006696 if (maybe_result->IsFailure()) return maybe_result;
6697
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006698 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006699 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006700 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006701 }
6702 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006703 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006704 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006705 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006706
6707 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006708 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006709 } else if (array_length == 1) {
6710 Object* first = fixed_array->get(0);
6711 if (first->IsString()) return first;
6712 }
6713
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006714 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006715 int position = 0;
6716 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006717 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006718 Object* elt = fixed_array->get(i);
6719 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006720 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006721 int smi_value = Smi::cast(elt)->value();
6722 int pos;
6723 int len;
6724 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006725 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006726 pos = StringBuilderSubstringPosition::decode(smi_value);
6727 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006728 } else {
6729 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006730 len = -smi_value;
6731 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006732 i++;
6733 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006734 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006735 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006736 Object* next_smi = fixed_array->get(i);
6737 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006738 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006739 }
6740 pos = Smi::cast(next_smi)->value();
6741 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006742 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006743 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006744 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006745 ASSERT(pos >= 0);
6746 ASSERT(len >= 0);
6747 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006748 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006749 }
6750 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006751 } else if (elt->IsString()) {
6752 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006753 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006754 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006755 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006756 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006757 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006758 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006759 ASSERT(!elt->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006760 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006761 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006762 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006763 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006764 return Failure::OutOfMemoryException();
6765 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006766 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006767 }
6768
6769 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006770 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006771
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006772 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006773 { MaybeObject* maybe_object =
6774 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006775 if (!maybe_object->ToObject(&object)) return maybe_object;
6776 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006777 SeqAsciiString* answer = SeqAsciiString::cast(object);
6778 StringBuilderConcatHelper(special,
6779 answer->GetChars(),
6780 fixed_array,
6781 array_length);
6782 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006783 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006784 { MaybeObject* maybe_object =
6785 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006786 if (!maybe_object->ToObject(&object)) return maybe_object;
6787 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006788 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6789 StringBuilderConcatHelper(special,
6790 answer->GetChars(),
6791 fixed_array,
6792 array_length);
6793 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006794 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006795}
6796
6797
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006798RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006799 NoHandleAllocation ha;
6800 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006801 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006802 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006803 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006804 return Failure::OutOfMemoryException();
6805 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006806 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006807 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006808
6809 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006810 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006811 }
6812 FixedArray* fixed_array = FixedArray::cast(array->elements());
6813 if (fixed_array->length() < array_length) {
6814 array_length = fixed_array->length();
6815 }
6816
6817 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006818 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006819 } else if (array_length == 1) {
6820 Object* first = fixed_array->get(0);
6821 if (first->IsString()) return first;
6822 }
6823
6824 int separator_length = separator->length();
6825 int max_nof_separators =
6826 (String::kMaxLength + separator_length - 1) / separator_length;
6827 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006828 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006829 return Failure::OutOfMemoryException();
6830 }
6831 int length = (array_length - 1) * separator_length;
6832 for (int i = 0; i < array_length; i++) {
6833 Object* element_obj = fixed_array->get(i);
6834 if (!element_obj->IsString()) {
6835 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006836 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006837 }
6838 String* element = String::cast(element_obj);
6839 int increment = element->length();
6840 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006841 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006842 return Failure::OutOfMemoryException();
6843 }
6844 length += increment;
6845 }
6846
6847 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006848 { MaybeObject* maybe_object =
6849 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006850 if (!maybe_object->ToObject(&object)) return maybe_object;
6851 }
6852 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6853
6854 uc16* sink = answer->GetChars();
6855#ifdef DEBUG
6856 uc16* end = sink + length;
6857#endif
6858
6859 String* first = String::cast(fixed_array->get(0));
6860 int first_length = first->length();
6861 String::WriteToFlat(first, sink, 0, first_length);
6862 sink += first_length;
6863
6864 for (int i = 1; i < array_length; i++) {
6865 ASSERT(sink + separator_length <= end);
6866 String::WriteToFlat(separator, sink, 0, separator_length);
6867 sink += separator_length;
6868
6869 String* element = String::cast(fixed_array->get(i));
6870 int element_length = element->length();
6871 ASSERT(sink + element_length <= end);
6872 String::WriteToFlat(element, sink, 0, element_length);
6873 sink += element_length;
6874 }
6875 ASSERT(sink == end);
6876
6877 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6878 return answer;
6879}
6880
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006881template <typename Char>
6882static void JoinSparseArrayWithSeparator(FixedArray* elements,
6883 int elements_length,
6884 uint32_t array_length,
6885 String* separator,
6886 Vector<Char> buffer) {
6887 int previous_separator_position = 0;
6888 int separator_length = separator->length();
6889 int cursor = 0;
6890 for (int i = 0; i < elements_length; i += 2) {
6891 int position = NumberToInt32(elements->get(i));
6892 String* string = String::cast(elements->get(i + 1));
6893 int string_length = string->length();
6894 if (string->length() > 0) {
6895 while (previous_separator_position < position) {
6896 String::WriteToFlat<Char>(separator, &buffer[cursor],
6897 0, separator_length);
6898 cursor += separator_length;
6899 previous_separator_position++;
6900 }
6901 String::WriteToFlat<Char>(string, &buffer[cursor],
6902 0, string_length);
6903 cursor += string->length();
6904 }
6905 }
6906 if (separator_length > 0) {
6907 // Array length must be representable as a signed 32-bit number,
6908 // otherwise the total string length would have been too large.
6909 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6910 int last_array_index = static_cast<int>(array_length - 1);
6911 while (previous_separator_position < last_array_index) {
6912 String::WriteToFlat<Char>(separator, &buffer[cursor],
6913 0, separator_length);
6914 cursor += separator_length;
6915 previous_separator_position++;
6916 }
6917 }
6918 ASSERT(cursor <= buffer.length());
6919}
6920
6921
6922RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6923 NoHandleAllocation ha;
6924 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006925 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006926 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6927 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006928 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006929 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006930 // elements_array is fast-mode JSarray of alternating positions
6931 // (increasing order) and strings.
6932 // array_length is length of original array (used to add separators);
6933 // separator is string to put between elements. Assumed to be non-empty.
6934
6935 // Find total length of join result.
6936 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006937 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006938 int max_string_length;
6939 if (is_ascii) {
6940 max_string_length = SeqAsciiString::kMaxLength;
6941 } else {
6942 max_string_length = SeqTwoByteString::kMaxLength;
6943 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006944 bool overflow = false;
6945 CONVERT_NUMBER_CHECKED(int, elements_length,
6946 Int32, elements_array->length());
6947 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6948 FixedArray* elements = FixedArray::cast(elements_array->elements());
6949 for (int i = 0; i < elements_length; i += 2) {
6950 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006951 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
6952 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006953 int length = string->length();
6954 if (is_ascii && !string->IsAsciiRepresentation()) {
6955 is_ascii = false;
6956 max_string_length = SeqTwoByteString::kMaxLength;
6957 }
6958 if (length > max_string_length ||
6959 max_string_length - length < string_length) {
6960 overflow = true;
6961 break;
6962 }
6963 string_length += length;
6964 }
6965 int separator_length = separator->length();
6966 if (!overflow && separator_length > 0) {
6967 if (array_length <= 0x7fffffffu) {
6968 int separator_count = static_cast<int>(array_length) - 1;
6969 int remaining_length = max_string_length - string_length;
6970 if ((remaining_length / separator_length) >= separator_count) {
6971 string_length += separator_length * (array_length - 1);
6972 } else {
6973 // Not room for the separators within the maximal string length.
6974 overflow = true;
6975 }
6976 } else {
6977 // Nonempty separator and at least 2^31-1 separators necessary
6978 // means that the string is too large to create.
6979 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6980 overflow = true;
6981 }
6982 }
6983 if (overflow) {
6984 // Throw OutOfMemory exception for creating too large a string.
6985 V8::FatalProcessOutOfMemory("Array join result too large.");
6986 }
6987
6988 if (is_ascii) {
6989 MaybeObject* result_allocation =
6990 isolate->heap()->AllocateRawAsciiString(string_length);
6991 if (result_allocation->IsFailure()) return result_allocation;
6992 SeqAsciiString* result_string =
6993 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6994 JoinSparseArrayWithSeparator<char>(elements,
6995 elements_length,
6996 array_length,
6997 separator,
6998 Vector<char>(result_string->GetChars(),
6999 string_length));
7000 return result_string;
7001 } else {
7002 MaybeObject* result_allocation =
7003 isolate->heap()->AllocateRawTwoByteString(string_length);
7004 if (result_allocation->IsFailure()) return result_allocation;
7005 SeqTwoByteString* result_string =
7006 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7007 JoinSparseArrayWithSeparator<uc16>(elements,
7008 elements_length,
7009 array_length,
7010 separator,
7011 Vector<uc16>(result_string->GetChars(),
7012 string_length));
7013 return result_string;
7014 }
7015}
7016
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007017
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007018RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007019 NoHandleAllocation ha;
7020 ASSERT(args.length() == 2);
7021
7022 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7023 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007024 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007025}
7026
7027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007028RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007029 NoHandleAllocation ha;
7030 ASSERT(args.length() == 2);
7031
7032 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7033 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007034 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007035}
7036
7037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007038RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007039 NoHandleAllocation ha;
7040 ASSERT(args.length() == 2);
7041
7042 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7043 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007044 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007045}
7046
7047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007048RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007049 NoHandleAllocation ha;
7050 ASSERT(args.length() == 1);
7051
7052 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007053 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007054}
7055
7056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007057RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007058 NoHandleAllocation ha;
7059 ASSERT(args.length() == 2);
7060
7061 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7062 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007063 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007064}
7065
7066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007067RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068 NoHandleAllocation ha;
7069 ASSERT(args.length() == 2);
7070
7071 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7072 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007073 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007074}
7075
7076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007077RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007078 NoHandleAllocation ha;
7079 ASSERT(args.length() == 2);
7080
7081 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7082 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007083 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007084}
7085
7086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007087RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007088 NoHandleAllocation ha;
7089 ASSERT(args.length() == 2);
7090
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007091 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7092 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007093 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7094 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7095 if (x == y) return Smi::FromInt(EQUAL);
7096 Object* result;
7097 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7098 result = Smi::FromInt(EQUAL);
7099 } else {
7100 result = Smi::FromInt(NOT_EQUAL);
7101 }
7102 return result;
7103}
7104
7105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007106RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007107 NoHandleAllocation ha;
7108 ASSERT(args.length() == 2);
7109
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007110 CONVERT_ARG_CHECKED(String, x, 0);
7111 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007112
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007113 bool not_equal = !x->Equals(y);
7114 // This is slightly convoluted because the value that signifies
7115 // equality is 0 and inequality is 1 so we have to negate the result
7116 // from String::Equals.
7117 ASSERT(not_equal == 0 || not_equal == 1);
7118 STATIC_CHECK(EQUAL == 0);
7119 STATIC_CHECK(NOT_EQUAL == 1);
7120 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007121}
7122
7123
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007124RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007125 NoHandleAllocation ha;
7126 ASSERT(args.length() == 3);
7127
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007128 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7129 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007130 if (isnan(x) || isnan(y)) return args[2];
7131 if (x == y) return Smi::FromInt(EQUAL);
7132 if (isless(x, y)) return Smi::FromInt(LESS);
7133 return Smi::FromInt(GREATER);
7134}
7135
7136
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007137// Compare two Smis as if they were converted to strings and then
7138// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007139RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007140 NoHandleAllocation ha;
7141 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007142 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7143 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007144
7145 // If the integers are equal so are the string representations.
7146 if (x_value == y_value) return Smi::FromInt(EQUAL);
7147
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007148 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007149 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007150 if (x_value == 0 || y_value == 0)
7151 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007152
ager@chromium.org32912102009-01-16 10:38:43 +00007153 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007154 // smallest because the char code of '-' is less than the char code
7155 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007156
7157 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7158 // architectures using 32-bit Smis.
7159 uint32_t x_scaled = x_value;
7160 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007161 if (x_value < 0 || y_value < 0) {
7162 if (y_value >= 0) return Smi::FromInt(LESS);
7163 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007164 x_scaled = -x_value;
7165 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007166 }
7167
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007168 static const uint32_t kPowersOf10[] = {
7169 1, 10, 100, 1000, 10*1000, 100*1000,
7170 1000*1000, 10*1000*1000, 100*1000*1000,
7171 1000*1000*1000
7172 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007173
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007174 // If the integers have the same number of decimal digits they can be
7175 // compared directly as the numeric order is the same as the
7176 // lexicographic order. If one integer has fewer digits, it is scaled
7177 // by some power of 10 to have the same number of digits as the longer
7178 // integer. If the scaled integers are equal it means the shorter
7179 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007180
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007181 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7182 int x_log2 = IntegerLog2(x_scaled);
7183 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7184 x_log10 -= x_scaled < kPowersOf10[x_log10];
7185
7186 int y_log2 = IntegerLog2(y_scaled);
7187 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7188 y_log10 -= y_scaled < kPowersOf10[y_log10];
7189
7190 int tie = EQUAL;
7191
7192 if (x_log10 < y_log10) {
7193 // X has fewer digits. We would like to simply scale up X but that
7194 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7195 // be scaled up to 9_000_000_000. So we scale up by the next
7196 // smallest power and scale down Y to drop one digit. It is OK to
7197 // drop one digit from the longer integer since the final digit is
7198 // past the length of the shorter integer.
7199 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7200 y_scaled /= 10;
7201 tie = LESS;
7202 } else if (y_log10 < x_log10) {
7203 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7204 x_scaled /= 10;
7205 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007206 }
7207
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007208 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7209 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7210 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007211}
7212
7213
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007214static Object* StringInputBufferCompare(RuntimeState* state,
7215 String* x,
7216 String* y) {
7217 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7218 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007219 bufx.Reset(x);
7220 bufy.Reset(y);
7221 while (bufx.has_more() && bufy.has_more()) {
7222 int d = bufx.GetNext() - bufy.GetNext();
7223 if (d < 0) return Smi::FromInt(LESS);
7224 else if (d > 0) return Smi::FromInt(GREATER);
7225 }
7226
7227 // x is (non-trivial) prefix of y:
7228 if (bufy.has_more()) return Smi::FromInt(LESS);
7229 // y is prefix of x:
7230 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7231}
7232
7233
7234static Object* FlatStringCompare(String* x, String* y) {
7235 ASSERT(x->IsFlat());
7236 ASSERT(y->IsFlat());
7237 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7238 int prefix_length = x->length();
7239 if (y->length() < prefix_length) {
7240 prefix_length = y->length();
7241 equal_prefix_result = Smi::FromInt(GREATER);
7242 } else if (y->length() > prefix_length) {
7243 equal_prefix_result = Smi::FromInt(LESS);
7244 }
7245 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007246 String::FlatContent x_content = x->GetFlatContent();
7247 String::FlatContent y_content = y->GetFlatContent();
7248 if (x_content.IsAscii()) {
7249 Vector<const char> x_chars = x_content.ToAsciiVector();
7250 if (y_content.IsAscii()) {
7251 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007252 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007253 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007254 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007255 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7256 }
7257 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007258 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7259 if (y_content.IsAscii()) {
7260 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007261 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7262 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007263 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007264 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7265 }
7266 }
7267 Object* result;
7268 if (r == 0) {
7269 result = equal_prefix_result;
7270 } else {
7271 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7272 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007273 ASSERT(result ==
7274 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007275 return result;
7276}
7277
7278
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007279RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007280 NoHandleAllocation ha;
7281 ASSERT(args.length() == 2);
7282
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007283 CONVERT_ARG_CHECKED(String, x, 0);
7284 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007285
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007286 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007287
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007288 // A few fast case tests before we flatten.
7289 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007290 if (y->length() == 0) {
7291 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007292 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007293 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007294 return Smi::FromInt(LESS);
7295 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007296
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007297 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007298 if (d < 0) return Smi::FromInt(LESS);
7299 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007300
lrn@chromium.org303ada72010-10-27 09:33:13 +00007301 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007302 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007303 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7304 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007305 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007306 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7307 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007308
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007309 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007310 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311}
7312
7313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007314RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007315 NoHandleAllocation ha;
7316 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007317 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007318
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007319 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007320 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321}
7322
7323
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007324RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007325 NoHandleAllocation ha;
7326 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007327 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007328
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007329 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007330 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007331}
7332
7333
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007334RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007335 NoHandleAllocation ha;
7336 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007337 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007338
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007339 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007340 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007341}
7342
7343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007344static const double kPiDividedBy4 = 0.78539816339744830962;
7345
7346
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007347RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007348 NoHandleAllocation ha;
7349 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007350 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007351
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007352 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7353 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007354 double result;
7355 if (isinf(x) && isinf(y)) {
7356 // Make sure that the result in case of two infinite arguments
7357 // is a multiple of Pi / 4. The sign of the result is determined
7358 // by the first argument (x) and the sign of the second argument
7359 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007360 int multiplier = (x < 0) ? -1 : 1;
7361 if (y < 0) multiplier *= 3;
7362 result = multiplier * kPiDividedBy4;
7363 } else {
7364 result = atan2(x, y);
7365 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007366 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007367}
7368
7369
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007370RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007371 NoHandleAllocation ha;
7372 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007373 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007375 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007376 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377}
7378
7379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007380RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007381 NoHandleAllocation ha;
7382 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007383 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007385 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007386 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387}
7388
7389
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007390RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007391 NoHandleAllocation ha;
7392 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007393 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007394
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007395 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007396 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397}
7398
7399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007400RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007401 NoHandleAllocation ha;
7402 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007403 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007404
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007405 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007406 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007407}
7408
7409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007410RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007411 NoHandleAllocation ha;
7412 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007413 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007414
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007415 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007416 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007417}
7418
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007419// Slow version of Math.pow. We check for fast paths for special cases.
7420// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007421RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007422 NoHandleAllocation ha;
7423 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007424 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007425
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007426 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007427
7428 // If the second argument is a smi, it is much faster to call the
7429 // custom powi() function than the generic pow().
7430 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007431 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007432 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007433 }
7434
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007435 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007436 int y_int = static_cast<int>(y);
7437 double result;
7438 if (y == y_int) {
7439 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7440 } else if (y == 0.5) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007441 result = (isinf(x)) ? V8_INFINITY
7442 : fast_sqrt(x + 0.0); // Convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007443 } else if (y == -0.5) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007444 result = (isinf(x)) ? 0
7445 : 1.0 / fast_sqrt(x + 0.0); // Convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007446 } else {
7447 result = power_double_double(x, y);
7448 }
7449 if (isnan(result)) return isolate->heap()->nan_value();
7450 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007451}
7452
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007453// Fast version of Math.pow if we know that y is not an integer and y is not
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007454// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007455RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007456 NoHandleAllocation ha;
7457 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007458 isolate->counters()->math_pow()->Increment();
7459
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007460 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7461 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007462 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007463 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007464 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007465 double result = power_double_double(x, y);
7466 if (isnan(result)) return isolate->heap()->nan_value();
7467 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007468 }
7469}
7470
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007471
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007472RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007473 NoHandleAllocation ha;
7474 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007475 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007476
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007477 if (!args[0]->IsHeapNumber()) {
7478 // Must be smi. Return the argument unchanged for all the other types
7479 // to make fuzz-natives test happy.
7480 return args[0];
7481 }
7482
7483 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7484
7485 double value = number->value();
7486 int exponent = number->get_exponent();
7487 int sign = number->get_sign();
7488
danno@chromium.org160a7b02011-04-18 15:51:38 +00007489 if (exponent < -1) {
7490 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7491 if (sign) return isolate->heap()->minus_zero_value();
7492 return Smi::FromInt(0);
7493 }
7494
7495 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7496 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007497 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007498 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007499 return Smi::FromInt(static_cast<int>(value + 0.5));
7500 }
7501
7502 // If the magnitude is big enough, there's no place for fraction part. If we
7503 // try to add 0.5 to this number, 1.0 will be added instead.
7504 if (exponent >= 52) {
7505 return number;
7506 }
7507
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007508 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007509
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007510 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007511 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007512}
7513
7514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007515RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007516 NoHandleAllocation ha;
7517 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007518 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007519
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007520 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007521 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007522}
7523
7524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007525RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007526 NoHandleAllocation ha;
7527 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007528 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007529
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007530 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007531 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007532}
7533
7534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007535RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007536 NoHandleAllocation ha;
7537 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007538 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007539
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007540 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007541 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007542}
7543
7544
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007545RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007546 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007547 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007548
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007549 CONVERT_SMI_ARG_CHECKED(year, 0);
7550 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007551
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007552 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007553}
7554
7555
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007556RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) {
7557 HandleScope scope(isolate);
7558 ASSERT(args.length() == 3);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007559
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007560 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
7561 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
7562 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007563
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007564 DateCache* date_cache = isolate->date_cache();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007565
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007566 Object* value = NULL;
7567 bool is_value_nan = false;
7568 if (isnan(time)) {
7569 value = isolate->heap()->nan_value();
7570 is_value_nan = true;
7571 } else if (!is_utc &&
7572 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
7573 time > DateCache::kMaxTimeBeforeUTCInMs)) {
7574 value = isolate->heap()->nan_value();
7575 is_value_nan = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007576 } else {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007577 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
7578 if (time < -DateCache::kMaxTimeInMs ||
7579 time > DateCache::kMaxTimeInMs) {
7580 value = isolate->heap()->nan_value();
7581 is_value_nan = true;
7582 } else {
7583 MaybeObject* maybe_result =
7584 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time));
7585 if (!maybe_result->ToObject(&value)) return maybe_result;
7586 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007587 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007588 date->SetValue(value, is_value_nan);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00007589 return value;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007590}
7591
7592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007593RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007594 HandleScope scope(isolate);
7595 ASSERT(args.length() == 3);
7596
7597 Handle<JSFunction> callee = args.at<JSFunction>(0);
7598 Object** parameters = reinterpret_cast<Object**>(args[1]);
7599 const int argument_count = Smi::cast(args[2])->value();
7600
7601 Handle<JSObject> result =
7602 isolate->factory()->NewArgumentsObject(callee, argument_count);
7603 // Allocate the elements if needed.
7604 int parameter_count = callee->shared()->formal_parameter_count();
7605 if (argument_count > 0) {
7606 if (parameter_count > 0) {
7607 int mapped_count = Min(argument_count, parameter_count);
7608 Handle<FixedArray> parameter_map =
7609 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7610 parameter_map->set_map(
7611 isolate->heap()->non_strict_arguments_elements_map());
7612
7613 Handle<Map> old_map(result->map());
7614 Handle<Map> new_map =
7615 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007616 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007617
7618 result->set_map(*new_map);
7619 result->set_elements(*parameter_map);
7620
7621 // Store the context and the arguments array at the beginning of the
7622 // parameter map.
7623 Handle<Context> context(isolate->context());
7624 Handle<FixedArray> arguments =
7625 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7626 parameter_map->set(0, *context);
7627 parameter_map->set(1, *arguments);
7628
7629 // Loop over the actual parameters backwards.
7630 int index = argument_count - 1;
7631 while (index >= mapped_count) {
7632 // These go directly in the arguments array and have no
7633 // corresponding slot in the parameter map.
7634 arguments->set(index, *(parameters - index - 1));
7635 --index;
7636 }
7637
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007638 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007639 while (index >= 0) {
7640 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007641 Handle<String> name(scope_info->ParameterName(index));
7642 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007643 bool duplicate = false;
7644 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007645 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007646 duplicate = true;
7647 break;
7648 }
7649 }
7650
7651 if (duplicate) {
7652 // This goes directly in the arguments array with a hole in the
7653 // parameter map.
7654 arguments->set(index, *(parameters - index - 1));
7655 parameter_map->set_the_hole(index + 2);
7656 } else {
7657 // The context index goes in the parameter map with a hole in the
7658 // arguments array.
7659 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007660 for (int j = 0; j < context_local_count; ++j) {
7661 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007662 context_index = j;
7663 break;
7664 }
7665 }
7666 ASSERT(context_index >= 0);
7667 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007668 parameter_map->set(index + 2, Smi::FromInt(
7669 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007670 }
7671
7672 --index;
7673 }
7674 } else {
7675 // If there is no aliasing, the arguments object elements are not
7676 // special in any way.
7677 Handle<FixedArray> elements =
7678 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7679 result->set_elements(*elements);
7680 for (int i = 0; i < argument_count; ++i) {
7681 elements->set(i, *(parameters - i - 1));
7682 }
7683 }
7684 }
7685 return *result;
7686}
7687
7688
7689RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007690 NoHandleAllocation ha;
7691 ASSERT(args.length() == 3);
7692
7693 JSFunction* callee = JSFunction::cast(args[0]);
7694 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007695 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007696
lrn@chromium.org303ada72010-10-27 09:33:13 +00007697 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007698 { MaybeObject* maybe_result =
7699 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007700 if (!maybe_result->ToObject(&result)) return maybe_result;
7701 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007702 // Allocate the elements if needed.
7703 if (length > 0) {
7704 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007705 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007706 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007707 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7708 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007709
7710 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007711 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007712 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007713 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007714
7715 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007716 for (int i = 0; i < length; i++) {
7717 array->set(i, *--parameters, mode);
7718 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007719 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007720 }
7721 return result;
7722}
7723
7724
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007725RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007726 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007727 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007728 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
7729 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
7730 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007731
whesse@chromium.org7b260152011-06-20 15:33:18 +00007732 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007733 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007734 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007735 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007736 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7737 context,
7738 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007739 return *result;
7740}
7741
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007742
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007743// Find the arguments of the JavaScript function invocation that called
7744// into C++ code. Collect these in a newly allocated array of handles (possibly
7745// prefixed by a number of empty handles).
7746static SmartArrayPointer<Handle<Object> > GetCallerArguments(
7747 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007748 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007749 // Find frame containing arguments passed to the caller.
7750 JavaScriptFrameIterator it;
7751 JavaScriptFrame* frame = it.frame();
7752 List<JSFunction*> functions(2);
7753 frame->GetFunctions(&functions);
7754 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007755 int inlined_jsframe_index = functions.length() - 1;
7756 JSFunction* inlined_function = functions[inlined_jsframe_index];
7757 Vector<SlotRef> args_slots =
7758 SlotRef::ComputeSlotMappingForArguments(
7759 frame,
7760 inlined_jsframe_index,
7761 inlined_function->shared()->formal_parameter_count());
7762
7763 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007764
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007765 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007766 SmartArrayPointer<Handle<Object> > param_data(
7767 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007768 for (int i = 0; i < args_count; i++) {
7769 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007770 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007771 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007772
7773 args_slots.Dispose();
7774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007775 return param_data;
7776 } else {
7777 it.AdvanceToArgumentsFrame();
7778 frame = it.frame();
7779 int args_count = frame->ComputeParametersCount();
7780
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007781 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007782 SmartArrayPointer<Handle<Object> > param_data(
7783 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007784 for (int i = 0; i < args_count; i++) {
7785 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007786 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007787 }
7788 return param_data;
7789 }
7790}
7791
7792
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007793RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
7794 HandleScope scope(isolate);
7795 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007796 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007797 RUNTIME_ASSERT(args[3]->IsNumber());
7798 Handle<Object> bindee = args.at<Object>(1);
7799
7800 // TODO(lrn): Create bound function in C++ code from premade shared info.
7801 bound_function->shared()->set_bound(true);
7802 // Get all arguments of calling function (Function.prototype.bind).
7803 int argc = 0;
7804 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
7805 // Don't count the this-arg.
7806 if (argc > 0) {
7807 ASSERT(*arguments[0] == args[2]);
7808 argc--;
7809 } else {
7810 ASSERT(args[2]->IsUndefined());
7811 }
7812 // Initialize array of bindings (function, this, and any existing arguments
7813 // if the function was already bound).
7814 Handle<FixedArray> new_bindings;
7815 int i;
7816 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
7817 Handle<FixedArray> old_bindings(
7818 JSFunction::cast(*bindee)->function_bindings());
7819 new_bindings =
7820 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
7821 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
7822 i = 0;
7823 for (int n = old_bindings->length(); i < n; i++) {
7824 new_bindings->set(i, old_bindings->get(i));
7825 }
7826 } else {
7827 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
7828 new_bindings = isolate->factory()->NewFixedArray(array_size);
7829 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
7830 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
7831 i = 2;
7832 }
7833 // Copy arguments, skipping the first which is "this_arg".
7834 for (int j = 0; j < argc; j++, i++) {
7835 new_bindings->set(i, *arguments[j + 1]);
7836 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007837 new_bindings->set_map_no_write_barrier(
7838 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007839 bound_function->set_function_bindings(*new_bindings);
7840
7841 // Update length.
7842 Handle<String> length_symbol = isolate->factory()->length_symbol();
7843 Handle<Object> new_length(args.at<Object>(3));
7844 PropertyAttributes attr =
7845 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
7846 ForceSetProperty(bound_function, length_symbol, new_length, attr);
7847 return *bound_function;
7848}
7849
7850
7851RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
7852 HandleScope handles(isolate);
7853 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007854 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007855 if (callable->IsJSFunction()) {
7856 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
7857 if (function->shared()->bound()) {
7858 Handle<FixedArray> bindings(function->function_bindings());
7859 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
7860 return *isolate->factory()->NewJSArrayWithElements(bindings);
7861 }
7862 }
7863 return isolate->heap()->undefined_value();
7864}
7865
7866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007867RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007868 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007869 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007870 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007871 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007872 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007873
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007874 // The argument is a bound function. Extract its bound arguments
7875 // and callable.
7876 Handle<FixedArray> bound_args =
7877 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
7878 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
7879 Handle<Object> bound_function(
7880 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
7881 ASSERT(!bound_function->IsJSFunction() ||
7882 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007883
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007884 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007885 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007886 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007887 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007888 param_data[i] = Handle<Object>(bound_args->get(
7889 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007890 }
7891
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007892 if (!bound_function->IsJSFunction()) {
7893 bool exception_thrown;
7894 bound_function = Execution::TryGetConstructorDelegate(bound_function,
7895 &exception_thrown);
7896 if (exception_thrown) return Failure::Exception();
7897 }
7898 ASSERT(bound_function->IsJSFunction());
7899
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007900 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007901 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007902 Execution::New(Handle<JSFunction>::cast(bound_function),
7903 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007904 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007905 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007906 }
7907 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007908 return *result;
7909}
7910
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007911
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007912static void TrySettingInlineConstructStub(Isolate* isolate,
7913 Handle<JSFunction> function) {
7914 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007915 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007916 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007917 }
7918 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007919 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007920 Handle<Code> code = compiler.CompileConstructStub(function);
7921 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007922 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007923}
7924
7925
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007926RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007927 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007928 ASSERT(args.length() == 1);
7929
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007930 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007931
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007932 // If the constructor isn't a proper function we throw a type error.
7933 if (!constructor->IsJSFunction()) {
7934 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7935 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007936 isolate->factory()->NewTypeError("not_constructor", arguments);
7937 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007938 }
7939
7940 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007941
7942 // If function should not have prototype, construction is not allowed. In this
7943 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007944 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007945 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7946 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007947 isolate->factory()->NewTypeError("not_constructor", arguments);
7948 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007949 }
7950
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007951#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007952 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007953 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007954 if (debug->StepInActive()) {
7955 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007956 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007957#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007958
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007959 if (function->has_initial_map()) {
7960 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007961 // The 'Function' function ignores the receiver object when
7962 // called using 'new' and creates a new JSFunction object that
7963 // is returned. The receiver object is only used for error
7964 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007965 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007966 // allocate JSFunctions since it does not properly initialize
7967 // the shared part of the function. Since the receiver is
7968 // ignored anyway, we use the global object as the receiver
7969 // instead of a new JSFunction object. This way, errors are
7970 // reported the same way whether or not 'Function' is called
7971 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007972 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007973 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007974 }
7975
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007976 // The function should be compiled for the optimization hints to be
7977 // available. We cannot use EnsureCompiled because that forces a
7978 // compilation through the shared function info which makes it
7979 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007980 if (!function->is_compiled()) {
7981 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
7982 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007983
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007984 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007985 if (!function->has_initial_map() &&
7986 shared->IsInobjectSlackTrackingInProgress()) {
7987 // The tracking is already in progress for another function. We can only
7988 // track one initial_map at a time, so we force the completion before the
7989 // function is called as a constructor for the first time.
7990 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007991 }
7992
7993 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007994 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7995 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007996 // Delay setting the stub if inobject slack tracking is in progress.
7997 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007998 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007999 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008000
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008001 isolate->counters()->constructed_objects()->Increment();
8002 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008003
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008004 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008005}
8006
8007
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008008RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008009 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008010 ASSERT(args.length() == 1);
8011
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008012 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008013 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008014 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008015
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008016 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008017}
8018
8019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008020RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008021 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008022 ASSERT(args.length() == 1);
8023
8024 Handle<JSFunction> function = args.at<JSFunction>(0);
8025#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008026 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008027 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008028 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008029 PrintF("]\n");
8030 }
8031#endif
8032
lrn@chromium.org34e60782011-09-15 07:25:40 +00008033 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008034 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008035 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008036 return Failure::Exception();
8037 }
8038
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008039 // All done. Return the compiled code.
8040 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008041 return function->code();
8042}
8043
8044
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008045RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008046 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008047 ASSERT(args.length() == 1);
8048 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008049
8050 // If the function is not compiled ignore the lazy
8051 // recompilation. This can happen if the debugger is activated and
8052 // the function is returned to the not compiled state.
8053 if (!function->shared()->is_compiled()) {
8054 function->ReplaceCode(function->shared()->code());
8055 return function->code();
8056 }
8057
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008058 // If the function is not optimizable or debugger is active continue using the
8059 // code from the full compiler.
8060 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008061 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008062 if (FLAG_trace_opt) {
8063 PrintF("[failed to optimize ");
8064 function->PrintName();
8065 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8066 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008067 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008068 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008069 function->ReplaceCode(function->shared()->code());
8070 return function->code();
8071 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00008072 function->shared()->code()->set_profiler_ticks(0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008073 if (JSFunction::CompileOptimized(function,
8074 AstNode::kNoNumber,
8075 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008076 return function->code();
8077 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008078 if (FLAG_trace_opt) {
8079 PrintF("[failed to optimize ");
8080 function->PrintName();
8081 PrintF(": optimized compilation failed]\n");
8082 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008083 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008084 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008085}
8086
8087
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008088class ActivationsFinder : public ThreadVisitor {
8089 public:
8090 explicit ActivationsFinder(JSFunction* function)
8091 : function_(function), has_activations_(false) {}
8092
8093 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8094 if (has_activations_) return;
8095
8096 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8097 JavaScriptFrame* frame = it.frame();
8098 if (frame->is_optimized() && frame->function() == function_) {
8099 has_activations_ = true;
8100 return;
8101 }
8102 }
8103 }
8104
8105 bool has_activations() { return has_activations_; }
8106
8107 private:
8108 JSFunction* function_;
8109 bool has_activations_;
8110};
8111
8112
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008113static void MaterializeArgumentsObjectInFrame(Isolate* isolate,
8114 JavaScriptFrame* frame) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008115 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008116 Handle<Object> arguments;
8117 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008118 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008119 if (arguments.is_null()) {
8120 // FunctionGetArguments can't throw an exception, so cast away the
8121 // doubt with an assert.
8122 arguments = Handle<Object>(
8123 Accessors::FunctionGetArguments(*function,
8124 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008125 ASSERT(*arguments != isolate->heap()->null_value());
8126 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008127 }
8128 frame->SetExpression(i, *arguments);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00008129 if (FLAG_trace_deopt) {
8130 PrintF("Materializing arguments object for frame %p - %p: %p ",
8131 reinterpret_cast<void*>(frame->sp()),
8132 reinterpret_cast<void*>(frame->fp()),
8133 reinterpret_cast<void*>(*arguments));
8134 arguments->ShortPrint();
8135 PrintF("\n");
8136 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008137 }
8138 }
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008139}
8140
8141
8142RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
8143 HandleScope scope(isolate);
8144 ASSERT(args.length() == 1);
8145 RUNTIME_ASSERT(args[0]->IsSmi());
8146 Deoptimizer::BailoutType type =
8147 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
8148 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8149 ASSERT(isolate->heap()->IsAllocationAllowed());
8150 int jsframes = deoptimizer->jsframe_count();
8151
8152 deoptimizer->MaterializeHeapNumbers();
8153 delete deoptimizer;
8154
8155 JavaScriptFrameIterator it(isolate);
8156 for (int i = 0; i < jsframes - 1; i++) {
8157 MaterializeArgumentsObjectInFrame(isolate, it.frame());
8158 it.Advance();
8159 }
8160
8161 JavaScriptFrame* frame = it.frame();
8162 RUNTIME_ASSERT(frame->function()->IsJSFunction());
8163 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
8164 MaterializeArgumentsObjectInFrame(isolate, frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008165
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008166 if (type == Deoptimizer::EAGER) {
8167 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008168 }
8169
8170 // Avoid doing too much work when running with --always-opt and keep
8171 // the optimized code around.
8172 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008173 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008174 }
8175
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008176 // Find other optimized activations of the function.
8177 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008178 while (!it.done()) {
8179 JavaScriptFrame* frame = it.frame();
8180 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008181 has_other_activations = true;
8182 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008183 }
8184 it.Advance();
8185 }
8186
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008187 if (!has_other_activations) {
8188 ActivationsFinder activations_finder(*function);
8189 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8190 has_other_activations = activations_finder.has_activations();
8191 }
8192
8193 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008194 if (FLAG_trace_deopt) {
8195 PrintF("[removing optimized code for: ");
8196 function->PrintName();
8197 PrintF("]\n");
8198 }
8199 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008200 } else {
8201 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008202 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008203 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008204}
8205
8206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008207RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008208 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008209 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008210 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008211}
8212
8213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008214RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008215 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008216 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008217 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008218 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008219
8220 Deoptimizer::DeoptimizeFunction(*function);
8221
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008222 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008223}
8224
8225
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008226RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8227#if defined(USE_SIMULATOR)
8228 return isolate->heap()->true_value();
8229#else
8230 return isolate->heap()->false_value();
8231#endif
8232}
8233
8234
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008235RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8236 HandleScope scope(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008237 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008238 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008239
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008240 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8241 function->MarkForLazyRecompilation();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008242
8243 Code* unoptimized = function->shared()->code();
8244 if (args.length() == 2 &&
8245 unoptimized->kind() == Code::FUNCTION) {
8246 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8247 CHECK(type->IsEqualTo(CStrVector("osr")));
8248 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8249 unoptimized->set_allow_osr_at_loop_nesting_level(
8250 Code::kMaxLoopNestingMarker);
8251 }
8252
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008253 return isolate->heap()->undefined_value();
8254}
8255
8256
lrn@chromium.org1c092762011-05-09 09:42:16 +00008257RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8258 HandleScope scope(isolate);
8259 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008260 // The least significant bit (after untagging) indicates whether the
8261 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008262 if (!V8::UseCrankshaft()) {
8263 return Smi::FromInt(4); // 4 == "never".
8264 }
8265 if (FLAG_always_opt) {
8266 return Smi::FromInt(3); // 3 == "always".
8267 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008268 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008269 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8270 : Smi::FromInt(2); // 2 == "no".
8271}
8272
8273
8274RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8275 HandleScope scope(isolate);
8276 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008277 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008278 return Smi::FromInt(function->shared()->opt_count());
8279}
8280
8281
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008282RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008283 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008284 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008285 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008286
8287 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008288 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008289
8290 // We have hit a back edge in an unoptimized frame for a function that was
8291 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008292 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008293 // Keep track of whether we've succeeded in optimizing.
8294 bool succeeded = unoptimized->optimizable();
8295 if (succeeded) {
8296 // If we are trying to do OSR when there are already optimized
8297 // activations of the function, it means (a) the function is directly or
8298 // indirectly recursive and (b) an optimized invocation has been
8299 // deoptimized so that we are currently in an unoptimized activation.
8300 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008301 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008302 while (succeeded && !it.done()) {
8303 JavaScriptFrame* frame = it.frame();
8304 succeeded = !frame->is_optimized() || frame->function() != *function;
8305 it.Advance();
8306 }
8307 }
8308
8309 int ast_id = AstNode::kNoNumber;
8310 if (succeeded) {
8311 // The top JS function is this one, the PC is somewhere in the
8312 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008313 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008314 JavaScriptFrame* frame = it.frame();
8315 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008316 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008317 ASSERT(unoptimized->contains(frame->pc()));
8318
8319 // Use linear search of the unoptimized code's stack check table to find
8320 // the AST id matching the PC.
8321 Address start = unoptimized->instruction_start();
8322 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008323 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008324 uint32_t table_length = Memory::uint32_at(table_cursor);
8325 table_cursor += kIntSize;
8326 for (unsigned i = 0; i < table_length; ++i) {
8327 // Table entries are (AST id, pc offset) pairs.
8328 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8329 if (pc_offset == target_pc_offset) {
8330 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8331 break;
8332 }
8333 table_cursor += 2 * kIntSize;
8334 }
8335 ASSERT(ast_id != AstNode::kNoNumber);
8336 if (FLAG_trace_osr) {
8337 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8338 function->PrintName();
8339 PrintF("]\n");
8340 }
8341
8342 // Try to compile the optimized code. A true return value from
8343 // CompileOptimized means that compilation succeeded, not necessarily
8344 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008345 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008346 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008347 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8348 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008349 if (data->OsrPcOffset()->value() >= 0) {
8350 if (FLAG_trace_osr) {
8351 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008352 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008353 }
8354 ASSERT(data->OsrAstId()->value() == ast_id);
8355 } else {
8356 // We may never generate the desired OSR entry if we emit an
8357 // early deoptimize.
8358 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008359 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008360 } else {
8361 succeeded = false;
8362 }
8363 }
8364
8365 // Revert to the original stack checks in the original unoptimized code.
8366 if (FLAG_trace_osr) {
8367 PrintF("[restoring original stack checks in ");
8368 function->PrintName();
8369 PrintF("]\n");
8370 }
yangguo@chromium.org56454712012-02-16 15:33:53 +00008371 Handle<Code> check_code;
yangguo@chromium.org56454712012-02-16 15:33:53 +00008372 if (FLAG_count_based_interrupts) {
8373 InterruptStub interrupt_stub;
8374 check_code = interrupt_stub.GetCode();
8375 } else // NOLINT
yangguo@chromium.org56454712012-02-16 15:33:53 +00008376 { // NOLINT
8377 StackCheckStub check_stub;
8378 check_code = check_stub.GetCode();
8379 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008380 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008381 Deoptimizer::RevertStackCheckCode(*unoptimized,
8382 *check_code,
8383 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008384
8385 // Allow OSR only at nesting level zero again.
8386 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8387
8388 // If the optimization attempt succeeded, return the AST id tagged as a
8389 // smi. This tells the builtin that we need to translate the unoptimized
8390 // frame to an optimized one.
8391 if (succeeded) {
8392 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8393 return Smi::FromInt(ast_id);
8394 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008395 if (function->IsMarkedForLazyRecompilation()) {
8396 function->ReplaceCode(function->shared()->code());
8397 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008398 return Smi::FromInt(-1);
8399 }
8400}
8401
8402
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008403RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8404 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8405 return isolate->heap()->undefined_value();
8406}
8407
8408
danno@chromium.orgc612e022011-11-10 11:38:15 +00008409RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8410 HandleScope scope(isolate);
8411 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008412 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008413 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8414 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008415
8416 // If there are too many arguments, allocate argv via malloc.
8417 const int argv_small_size = 10;
8418 Handle<Object> argv_small_buffer[argv_small_size];
8419 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8420 Handle<Object>* argv = argv_small_buffer;
8421 if (argc > argv_small_size) {
8422 argv = new Handle<Object>[argc];
8423 if (argv == NULL) return isolate->StackOverflow();
8424 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8425 }
8426
8427 for (int i = 0; i < argc; ++i) {
8428 MaybeObject* maybe = args[1 + i];
8429 Object* object;
8430 if (!maybe->To<Object>(&object)) return maybe;
8431 argv[i] = Handle<Object>(object);
8432 }
8433
8434 bool threw;
8435 Handle<JSReceiver> hfun(fun);
8436 Handle<Object> hreceiver(receiver);
8437 Handle<Object> result =
8438 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8439
8440 if (threw) return Failure::Exception();
8441 return *result;
8442}
8443
8444
lrn@chromium.org34e60782011-09-15 07:25:40 +00008445RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8446 HandleScope scope(isolate);
8447 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008448 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008449 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008450 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008451 CONVERT_SMI_ARG_CHECKED(offset, 3);
8452 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008453 ASSERT(offset >= 0);
8454 ASSERT(argc >= 0);
8455
8456 // If there are too many arguments, allocate argv via malloc.
8457 const int argv_small_size = 10;
8458 Handle<Object> argv_small_buffer[argv_small_size];
8459 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8460 Handle<Object>* argv = argv_small_buffer;
8461 if (argc > argv_small_size) {
8462 argv = new Handle<Object>[argc];
8463 if (argv == NULL) return isolate->StackOverflow();
8464 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8465 }
8466
8467 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008468 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008469 }
8470
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008471 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008472 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008473 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008474
8475 if (threw) return Failure::Exception();
8476 return *result;
8477}
8478
8479
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008480RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008481 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008482 ASSERT(args.length() == 1);
8483 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8484 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8485}
8486
8487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008488RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008489 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008490 ASSERT(args.length() == 1);
8491 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8492 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8493}
8494
8495
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008496RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008497 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008498 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008499
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008500 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008501 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008502 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008503 { MaybeObject* maybe_result =
8504 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008505 if (!maybe_result->ToObject(&result)) return maybe_result;
8506 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008507
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008508 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008509
kasper.lund7276f142008-07-30 08:49:36 +00008510 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008511}
8512
lrn@chromium.org303ada72010-10-27 09:33:13 +00008513
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008514RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8515 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008516 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008517 JSObject* extension_object;
8518 if (args[0]->IsJSObject()) {
8519 extension_object = JSObject::cast(args[0]);
8520 } else {
8521 // Convert the object to a proper JavaScript object.
8522 MaybeObject* maybe_js_object = args[0]->ToObject();
8523 if (!maybe_js_object->To(&extension_object)) {
8524 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8525 HandleScope scope(isolate);
8526 Handle<Object> handle = args.at<Object>(0);
8527 Handle<Object> result =
8528 isolate->factory()->NewTypeError("with_expression",
8529 HandleVector(&handle, 1));
8530 return isolate->Throw(*result);
8531 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008532 return maybe_js_object;
8533 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008534 }
8535 }
8536
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008537 JSFunction* function;
8538 if (args[1]->IsSmi()) {
8539 // A smi sentinel indicates a context nested inside global code rather
8540 // than some function. There is a canonical empty function that can be
8541 // gotten from the global context.
8542 function = isolate->context()->global_context()->closure();
8543 } else {
8544 function = JSFunction::cast(args[1]);
8545 }
8546
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008547 Context* context;
8548 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008549 isolate->heap()->AllocateWithContext(function,
8550 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008551 extension_object);
8552 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008553 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008554 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008555}
8556
8557
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008558RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008559 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008560 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008561 String* name = String::cast(args[0]);
8562 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008563 JSFunction* function;
8564 if (args[2]->IsSmi()) {
8565 // A smi sentinel indicates a context nested inside global code rather
8566 // than some function. There is a canonical empty function that can be
8567 // gotten from the global context.
8568 function = isolate->context()->global_context()->closure();
8569 } else {
8570 function = JSFunction::cast(args[2]);
8571 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008572 Context* context;
8573 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008574 isolate->heap()->AllocateCatchContext(function,
8575 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008576 name,
8577 thrown_object);
8578 if (!maybe_context->To(&context)) return maybe_context;
8579 isolate->set_context(context);
8580 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008581}
8582
8583
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008584RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8585 NoHandleAllocation ha;
8586 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008587 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008588 JSFunction* function;
8589 if (args[1]->IsSmi()) {
8590 // A smi sentinel indicates a context nested inside global code rather
8591 // than some function. There is a canonical empty function that can be
8592 // gotten from the global context.
8593 function = isolate->context()->global_context()->closure();
8594 } else {
8595 function = JSFunction::cast(args[1]);
8596 }
8597 Context* context;
8598 MaybeObject* maybe_context =
8599 isolate->heap()->AllocateBlockContext(function,
8600 isolate->context(),
8601 scope_info);
8602 if (!maybe_context->To(&context)) return maybe_context;
8603 isolate->set_context(context);
8604 return context;
8605}
8606
8607
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008608RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008609 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008610 ASSERT(args.length() == 2);
8611
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008612 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8613 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008614
8615 int index;
8616 PropertyAttributes attributes;
8617 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008618 BindingFlags binding_flags;
8619 Handle<Object> holder = context->Lookup(name,
8620 flags,
8621 &index,
8622 &attributes,
8623 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008624
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008625 // If the slot was not found the result is true.
8626 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008627 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008628 }
8629
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008630 // If the slot was found in a context, it should be DONT_DELETE.
8631 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008632 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008633 }
8634
8635 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008636 // the global object, or the subject of a with. Try to delete it
8637 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008638 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008639 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008640}
8641
8642
ager@chromium.orga1645e22009-09-09 19:27:10 +00008643// A mechanism to return a pair of Object pointers in registers (if possible).
8644// How this is achieved is calling convention-dependent.
8645// All currently supported x86 compiles uses calling conventions that are cdecl
8646// variants where a 64-bit value is returned in two 32-bit registers
8647// (edx:eax on ia32, r1:r0 on ARM).
8648// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8649// In Win64 calling convention, a struct of two pointers is returned in memory,
8650// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008651#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008652struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008653 MaybeObject* x;
8654 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008655};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008656
lrn@chromium.org303ada72010-10-27 09:33:13 +00008657static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008658 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008659 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8660 // In Win64 they are assigned to a hidden first argument.
8661 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008662}
8663#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008664typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008665static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008666 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008667 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008668}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008669#endif
8670
8671
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008672static inline MaybeObject* Unhole(Heap* heap,
8673 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008674 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008675 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8676 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008677 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008678}
8679
8680
danno@chromium.org40cb8782011-05-25 07:58:50 +00008681static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8682 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008683 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008684 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008685 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008686 JSFunction* context_extension_function =
8687 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008688 // If the holder isn't a context extension object, we just return it
8689 // as the receiver. This allows arguments objects to be used as
8690 // receivers, but only if they are put in the context scope chain
8691 // explicitly via a with-statement.
8692 Object* constructor = holder->map()->constructor();
8693 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008694 // Fall back to using the global object as the implicit receiver if
8695 // the property turns out to be a local variable allocated in a
8696 // context extension object - introduced via eval. Implicit global
8697 // receivers are indicated with the hole value.
8698 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008699}
8700
8701
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008702static ObjectPair LoadContextSlotHelper(Arguments args,
8703 Isolate* isolate,
8704 bool throw_error) {
8705 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008706 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008707
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008708 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008709 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008710 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008711 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008712 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008713
8714 int index;
8715 PropertyAttributes attributes;
8716 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008717 BindingFlags binding_flags;
8718 Handle<Object> holder = context->Lookup(name,
8719 flags,
8720 &index,
8721 &attributes,
8722 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008723
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008724 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008725 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008726 ASSERT(holder->IsContext());
8727 // If the "property" we were looking for is a local variable, the
8728 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008729 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008730 // Use the hole as the receiver to signal that the receiver is implicit
8731 // and that the global receiver should be used (as distinguished from an
8732 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008733 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008734 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008735 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008736 switch (binding_flags) {
8737 case MUTABLE_CHECK_INITIALIZED:
8738 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
8739 if (value->IsTheHole()) {
8740 Handle<Object> reference_error =
8741 isolate->factory()->NewReferenceError("not_defined",
8742 HandleVector(&name, 1));
8743 return MakePair(isolate->Throw(*reference_error), NULL);
8744 }
8745 // FALLTHROUGH
8746 case MUTABLE_IS_INITIALIZED:
8747 case IMMUTABLE_IS_INITIALIZED:
8748 case IMMUTABLE_IS_INITIALIZED_HARMONY:
8749 ASSERT(!value->IsTheHole());
8750 return MakePair(value, *receiver);
8751 case IMMUTABLE_CHECK_INITIALIZED:
8752 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8753 case MISSING_BINDING:
8754 UNREACHABLE();
8755 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008756 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008757 }
8758
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008759 // Otherwise, if the slot was found the holder is a context extension
8760 // object, subject of a with, or a global object. We read the named
8761 // property from it.
8762 if (!holder.is_null()) {
8763 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8764 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008765 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008766 Handle<Object> receiver_handle(object->IsGlobalObject()
8767 ? GlobalObject::cast(*object)->global_receiver()
8768 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008769
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008770 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008771 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008772 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008773 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008774 }
8775
8776 if (throw_error) {
8777 // The property doesn't exist - throw exception.
8778 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008779 isolate->factory()->NewReferenceError("not_defined",
8780 HandleVector(&name, 1));
8781 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008782 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008783 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008784 return MakePair(isolate->heap()->undefined_value(),
8785 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008786 }
8787}
8788
8789
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008790RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008791 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008792}
8793
8794
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008795RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008796 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008797}
8798
8799
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008800RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008801 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008802 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008803
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008804 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008805 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
8806 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00008807 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
8808 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
8809 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008810
8811 int index;
8812 PropertyAttributes attributes;
8813 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008814 BindingFlags binding_flags;
8815 Handle<Object> holder = context->Lookup(name,
8816 flags,
8817 &index,
8818 &attributes,
8819 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008820
8821 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008822 // The property was found in a context slot.
8823 Handle<Context> context = Handle<Context>::cast(holder);
8824 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8825 context->get(index)->IsTheHole()) {
8826 Handle<Object> error =
8827 isolate->factory()->NewReferenceError("not_defined",
8828 HandleVector(&name, 1));
8829 return isolate->Throw(*error);
8830 }
8831 // Ignore if read_only variable.
8832 if ((attributes & READ_ONLY) == 0) {
8833 // Context is a fixed array and set cannot fail.
8834 context->set(index, *value);
8835 } else if (strict_mode == kStrictMode) {
8836 // Setting read only property in strict mode.
8837 Handle<Object> error =
8838 isolate->factory()->NewTypeError("strict_cannot_assign",
8839 HandleVector(&name, 1));
8840 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008841 }
8842 return *value;
8843 }
8844
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008845 // Slow case: The property is not in a context slot. It is either in a
8846 // context extension object, a property of the subject of a with, or a
8847 // property of the global object.
8848 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008849
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008850 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008851 // The property exists on the holder.
8852 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008853 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008854 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008855 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008856
8857 if (strict_mode == kStrictMode) {
8858 // Throw in strict mode (assignment to undefined variable).
8859 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008860 isolate->factory()->NewReferenceError(
8861 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008862 return isolate->Throw(*error);
8863 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008864 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008865 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008866 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008867 }
8868
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008869 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008870 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008871 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008872 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008873 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008874 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008875 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008876 // Setting read only property in strict mode.
8877 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008878 isolate->factory()->NewTypeError(
8879 "strict_cannot_assign", HandleVector(&name, 1));
8880 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008881 }
8882 return *value;
8883}
8884
8885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008886RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008887 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008888 ASSERT(args.length() == 1);
8889
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008890 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008891}
8892
8893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008894RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008895 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008896 ASSERT(args.length() == 1);
8897
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008898 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008899}
8900
8901
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008902RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008903 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008904 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008905}
8906
8907
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008908RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008909 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008910 ASSERT(args.length() == 1);
8911
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008912 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008913 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008914 isolate->factory()->NewReferenceError("not_defined",
8915 HandleVector(&name, 1));
8916 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008917}
8918
8919
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008920RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008921 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008922
8923 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008924 if (isolate->stack_guard()->IsStackOverflow()) {
8925 NoHandleAllocation na;
8926 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008927 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008928
ulan@chromium.org812308e2012-02-29 15:58:45 +00008929 return Execution::HandleStackGuardInterrupt(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008930}
8931
8932
yangguo@chromium.org56454712012-02-16 15:33:53 +00008933RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
8934 ASSERT(args.length() == 0);
ulan@chromium.org812308e2012-02-29 15:58:45 +00008935 return Execution::HandleStackGuardInterrupt(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00008936}
8937
8938
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008939static int StackSize() {
8940 int n = 0;
8941 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8942 return n;
8943}
8944
8945
8946static void PrintTransition(Object* result) {
8947 // indentation
8948 { const int nmax = 80;
8949 int n = StackSize();
8950 if (n <= nmax)
8951 PrintF("%4d:%*s", n, n, "");
8952 else
8953 PrintF("%4d:%*s", n, nmax, "...");
8954 }
8955
8956 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008957 JavaScriptFrame::PrintTop(stdout, true, false);
8958 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008959 } else {
8960 // function result
8961 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008962 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008963 PrintF("\n");
8964 }
8965}
8966
8967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008968RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008969 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008970 NoHandleAllocation ha;
8971 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008972 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008973}
8974
8975
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008976RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008977 NoHandleAllocation ha;
8978 PrintTransition(args[0]);
8979 return args[0]; // return TOS
8980}
8981
8982
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008983RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008984 NoHandleAllocation ha;
8985 ASSERT(args.length() == 1);
8986
8987#ifdef DEBUG
8988 if (args[0]->IsString()) {
8989 // If we have a string, assume it's a code "marker"
8990 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008991 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008992 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008993 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8994 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008995 } else {
8996 PrintF("DebugPrint: ");
8997 }
8998 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008999 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009000 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009001 HeapObject::cast(args[0])->map()->Print();
9002 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009003#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009004 // ShortPrint is available in release mode. Print is not.
9005 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009006#endif
9007 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009008 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009009
9010 return args[0]; // return TOS
9011}
9012
9013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009014RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009015 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009016 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009017 isolate->PrintStack();
9018 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009019}
9020
9021
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009022RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009023 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009024 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009025
9026 // According to ECMA-262, section 15.9.1, page 117, the precision of
9027 // the number in a Date object representing a particular instant in
9028 // time is milliseconds. Therefore, we floor the result of getting
9029 // the OS time.
9030 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009031 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009032}
9033
9034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009035RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009036 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009037 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009038
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009039 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009040 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009041
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009042 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009043
9044 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009045 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009046 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009047 RUNTIME_ASSERT(output->HasFastElements());
9048
9049 AssertNoAllocation no_allocation;
9050
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009051 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009052 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9053 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009054 String::FlatContent str_content = str->GetFlatContent();
9055 if (str_content.IsAscii()) {
9056 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009057 output_array,
9058 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009059 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009060 ASSERT(str_content.IsTwoByte());
9061 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009062 output_array,
9063 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009064 }
9065
9066 if (result) {
9067 return *output;
9068 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009069 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009070 }
9071}
9072
9073
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009074RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009075 NoHandleAllocation ha;
9076 ASSERT(args.length() == 1);
9077
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009078 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009079 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
9080 const char* zone = OS::LocalTimezone(static_cast<double>(time));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009081 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009082}
9083
9084
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009085RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009086 NoHandleAllocation ha;
9087 ASSERT(args.length() == 1);
9088
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009089 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009090 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
9091
9092 return isolate->heap()->NumberFromDouble(static_cast<double>(time));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009093}
9094
9095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009096RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009097 ASSERT(args.length() == 1);
9098 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009099 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009100 return JSGlobalObject::cast(global)->global_receiver();
9101}
9102
9103
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009104RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009105 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009106 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009107 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009108
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009109 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009110 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009111 Handle<Object> result;
9112 if (source->IsSeqAsciiString()) {
9113 result = JsonParser<true>::Parse(source);
9114 } else {
9115 result = JsonParser<false>::Parse(source);
9116 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009117 if (result.is_null()) {
9118 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009119 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009120 return Failure::Exception();
9121 }
9122 return *result;
9123}
9124
9125
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009126bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9127 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009128 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9129 // Check with callback if set.
9130 AllowCodeGenerationFromStringsCallback callback =
9131 isolate->allow_code_gen_callback();
9132 if (callback == NULL) {
9133 // No callback set and code generation disallowed.
9134 return false;
9135 } else {
9136 // Callback set. Let it decide if code generation is allowed.
9137 VMState state(isolate, EXTERNAL);
9138 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009139 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009140}
9141
9142
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009143RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009144 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009145 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009146 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009147
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009148 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009149 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009150
9151 // Check if global context allows code generation from
9152 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009153 if (context->allow_code_gen_from_strings()->IsFalse() &&
9154 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009155 return isolate->Throw(*isolate->factory()->NewError(
9156 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9157 }
9158
9159 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009160 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009161 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009162 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009163 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009164 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9165 context,
9166 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009167 return *fun;
9168}
9169
9170
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009171static ObjectPair CompileGlobalEval(Isolate* isolate,
9172 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009173 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009174 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009175 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009176 Handle<Context> context = Handle<Context>(isolate->context());
9177 Handle<Context> global_context = Handle<Context>(context->global_context());
9178
9179 // Check if global context allows code generation from
9180 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009181 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9182 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009183 isolate->Throw(*isolate->factory()->NewError(
9184 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9185 return MakePair(Failure::Exception(), NULL);
9186 }
9187
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009188 // Deal with a normal eval call with a string argument. Compile it
9189 // and return the compiled function bound in the local context.
9190 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9191 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009192 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009193 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009194 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009195 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009196 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009197 Handle<JSFunction> compiled =
9198 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009199 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009200 return MakePair(*compiled, *receiver);
9201}
9202
9203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009204RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009205 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009206
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009207 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009208 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009209
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009210 // If "eval" didn't refer to the original GlobalEval, it's not a
9211 // direct call to eval.
9212 // (And even if it is, but the first argument isn't a string, just let
9213 // execution default to an indirect call to eval, which will also return
9214 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009215 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009216 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009217 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009218 }
9219
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009220 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009221 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009222 return CompileGlobalEval(isolate,
9223 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009224 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009225 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009226 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009227}
9228
9229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009230RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009231 // This utility adjusts the property attributes for newly created Function
9232 // object ("new Function(...)") by changing the map.
9233 // All it does is changing the prototype property to enumerable
9234 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009235 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009236 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009237 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009238
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009239 Handle<Map> map = func->shared()->is_classic_mode()
9240 ? isolate->function_instance_map()
9241 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009242
9243 ASSERT(func->map()->instance_type() == map->instance_type());
9244 ASSERT(func->map()->instance_size() == map->instance_size());
9245 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009246 return *func;
9247}
9248
9249
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009250RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009251 // Allocate a block of memory in NewSpace (filled with a filler).
9252 // Use as fallback for allocation in generated code when NewSpace
9253 // is full.
9254 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009255 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009256 int size = size_smi->value();
9257 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9258 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009259 Heap* heap = isolate->heap();
9260 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009261 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009262 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009263 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009264 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009265 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009266 }
9267 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009268 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009269}
9270
9271
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009272// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009273// array. Returns true if the element was pushed on the stack and
9274// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009275RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009276 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009277 CONVERT_ARG_CHECKED(JSArray, array, 0);
9278 CONVERT_ARG_CHECKED(JSObject, element, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009279 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009280 int length = Smi::cast(array->length())->value();
9281 FixedArray* elements = FixedArray::cast(array->elements());
9282 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009283 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009284 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009285 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009286 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009287 { MaybeObject* maybe_obj =
9288 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009289 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9290 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009291 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009292}
9293
9294
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009295/**
9296 * A simple visitor visits every element of Array's.
9297 * The backend storage can be a fixed array for fast elements case,
9298 * or a dictionary for sparse array. Since Dictionary is a subtype
9299 * of FixedArray, the class can be used by both fast and slow cases.
9300 * The second parameter of the constructor, fast_elements, specifies
9301 * whether the storage is a FixedArray or Dictionary.
9302 *
9303 * An index limit is used to deal with the situation that a result array
9304 * length overflows 32-bit non-negative integer.
9305 */
9306class ArrayConcatVisitor {
9307 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009308 ArrayConcatVisitor(Isolate* isolate,
9309 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009310 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009311 isolate_(isolate),
9312 storage_(Handle<FixedArray>::cast(
9313 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009314 index_offset_(0u),
9315 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009316
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009317 ~ArrayConcatVisitor() {
9318 clear_storage();
9319 }
9320
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009321 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009322 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009323 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009324
9325 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009326 if (index < static_cast<uint32_t>(storage_->length())) {
9327 storage_->set(index, *elm);
9328 return;
9329 }
9330 // Our initial estimate of length was foiled, possibly by
9331 // getters on the arrays increasing the length of later arrays
9332 // during iteration.
9333 // This shouldn't happen in anything but pathological cases.
9334 SetDictionaryMode(index);
9335 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009336 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009337 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009338 Handle<SeededNumberDictionary> dict(
9339 SeededNumberDictionary::cast(*storage_));
9340 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009341 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009342 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009343 // Dictionary needed to grow.
9344 clear_storage();
9345 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009346 }
9347}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009348
9349 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009350 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9351 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009352 } else {
9353 index_offset_ += delta;
9354 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009355 }
9356
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009357 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009358 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009359 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009360 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009361 Handle<Map> map;
9362 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009363 map = isolate_->factory()->GetElementsTransitionMap(array,
9364 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009365 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009366 map = isolate_->factory()->GetElementsTransitionMap(array,
9367 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009368 }
9369 array->set_map(*map);
9370 array->set_length(*length);
9371 array->set_elements(*storage_);
9372 return array;
9373 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009374
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009375 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009376 // Convert storage to dictionary mode.
9377 void SetDictionaryMode(uint32_t index) {
9378 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009379 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009380 Handle<SeededNumberDictionary> slow_storage(
9381 isolate_->factory()->NewSeededNumberDictionary(
9382 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009383 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9384 for (uint32_t i = 0; i < current_length; i++) {
9385 HandleScope loop_scope;
9386 Handle<Object> element(current_storage->get(i));
9387 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009388 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009389 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009390 if (!new_storage.is_identical_to(slow_storage)) {
9391 slow_storage = loop_scope.CloseAndEscape(new_storage);
9392 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009393 }
9394 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009395 clear_storage();
9396 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009397 fast_elements_ = false;
9398 }
9399
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009400 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009401 isolate_->global_handles()->Destroy(
9402 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009403 }
9404
9405 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009406 storage_ = Handle<FixedArray>::cast(
9407 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009408 }
9409
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009410 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009411 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009412 // Index after last seen index. Always less than or equal to
9413 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009414 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009415 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009416};
9417
9418
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009419static uint32_t EstimateElementCount(Handle<JSArray> array) {
9420 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9421 int element_count = 0;
9422 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009423 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009424 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009425 // Fast elements can't have lengths that are not representable by
9426 // a 32-bit signed integer.
9427 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9428 int fast_length = static_cast<int>(length);
9429 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9430 for (int i = 0; i < fast_length; i++) {
9431 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009432 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009433 break;
9434 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009435 case FAST_DOUBLE_ELEMENTS:
9436 // TODO(1810): Decide if it's worthwhile to implement this.
9437 UNREACHABLE();
9438 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009439 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009440 Handle<SeededNumberDictionary> dictionary(
9441 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009442 int capacity = dictionary->Capacity();
9443 for (int i = 0; i < capacity; i++) {
9444 Handle<Object> key(dictionary->KeyAt(i));
9445 if (dictionary->IsKey(*key)) {
9446 element_count++;
9447 }
9448 }
9449 break;
9450 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009451 case NON_STRICT_ARGUMENTS_ELEMENTS:
9452 case EXTERNAL_BYTE_ELEMENTS:
9453 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9454 case EXTERNAL_SHORT_ELEMENTS:
9455 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9456 case EXTERNAL_INT_ELEMENTS:
9457 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9458 case EXTERNAL_FLOAT_ELEMENTS:
9459 case EXTERNAL_DOUBLE_ELEMENTS:
9460 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009461 // External arrays are always dense.
9462 return length;
9463 }
9464 // As an estimate, we assume that the prototype doesn't contain any
9465 // inherited elements.
9466 return element_count;
9467}
9468
9469
9470
9471template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009472static void IterateExternalArrayElements(Isolate* isolate,
9473 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009474 bool elements_are_ints,
9475 bool elements_are_guaranteed_smis,
9476 ArrayConcatVisitor* visitor) {
9477 Handle<ExternalArrayClass> array(
9478 ExternalArrayClass::cast(receiver->elements()));
9479 uint32_t len = static_cast<uint32_t>(array->length());
9480
9481 ASSERT(visitor != NULL);
9482 if (elements_are_ints) {
9483 if (elements_are_guaranteed_smis) {
9484 for (uint32_t j = 0; j < len; j++) {
9485 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009486 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009487 visitor->visit(j, e);
9488 }
9489 } else {
9490 for (uint32_t j = 0; j < len; j++) {
9491 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009492 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009493 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9494 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9495 visitor->visit(j, e);
9496 } else {
9497 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009498 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009499 visitor->visit(j, e);
9500 }
9501 }
9502 }
9503 } else {
9504 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009505 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009506 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009507 visitor->visit(j, e);
9508 }
9509 }
9510}
9511
9512
9513// Used for sorting indices in a List<uint32_t>.
9514static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9515 uint32_t a = *ap;
9516 uint32_t b = *bp;
9517 return (a == b) ? 0 : (a < b) ? -1 : 1;
9518}
9519
9520
9521static void CollectElementIndices(Handle<JSObject> object,
9522 uint32_t range,
9523 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009524 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009525 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009526 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009527 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009528 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9529 uint32_t length = static_cast<uint32_t>(elements->length());
9530 if (range < length) length = range;
9531 for (uint32_t i = 0; i < length; i++) {
9532 if (!elements->get(i)->IsTheHole()) {
9533 indices->Add(i);
9534 }
9535 }
9536 break;
9537 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009538 case FAST_DOUBLE_ELEMENTS: {
9539 // TODO(1810): Decide if it's worthwhile to implement this.
9540 UNREACHABLE();
9541 break;
9542 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009543 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009544 Handle<SeededNumberDictionary> dict(
9545 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009546 uint32_t capacity = dict->Capacity();
9547 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009548 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009549 Handle<Object> k(dict->KeyAt(j));
9550 if (dict->IsKey(*k)) {
9551 ASSERT(k->IsNumber());
9552 uint32_t index = static_cast<uint32_t>(k->Number());
9553 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009554 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009555 }
9556 }
9557 }
9558 break;
9559 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009560 default: {
9561 int dense_elements_length;
9562 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009563 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009564 dense_elements_length =
9565 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009566 break;
9567 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009568 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009569 dense_elements_length =
9570 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009571 break;
9572 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009573 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009574 dense_elements_length =
9575 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009576 break;
9577 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009578 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009579 dense_elements_length =
9580 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009581 break;
9582 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009583 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009584 dense_elements_length =
9585 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009586 break;
9587 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009588 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009589 dense_elements_length =
9590 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009591 break;
9592 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009593 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009594 dense_elements_length =
9595 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009596 break;
9597 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009598 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009599 dense_elements_length =
9600 ExternalFloatArray::cast(object->elements())->length();
9601 break;
9602 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009603 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009604 dense_elements_length =
9605 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009606 break;
9607 }
9608 default:
9609 UNREACHABLE();
9610 dense_elements_length = 0;
9611 break;
9612 }
9613 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9614 if (range <= length) {
9615 length = range;
9616 // We will add all indices, so we might as well clear it first
9617 // and avoid duplicates.
9618 indices->Clear();
9619 }
9620 for (uint32_t i = 0; i < length; i++) {
9621 indices->Add(i);
9622 }
9623 if (length == range) return; // All indices accounted for already.
9624 break;
9625 }
9626 }
9627
9628 Handle<Object> prototype(object->GetPrototype());
9629 if (prototype->IsJSObject()) {
9630 // The prototype will usually have no inherited element indices,
9631 // but we have to check.
9632 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9633 }
9634}
9635
9636
9637/**
9638 * A helper function that visits elements of a JSArray in numerical
9639 * order.
9640 *
9641 * The visitor argument called for each existing element in the array
9642 * with the element index and the element's value.
9643 * Afterwards it increments the base-index of the visitor by the array
9644 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009645 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009646 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009647static bool IterateElements(Isolate* isolate,
9648 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009649 ArrayConcatVisitor* visitor) {
9650 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9651 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009652 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009653 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009654 // Run through the elements FixedArray and use HasElement and GetElement
9655 // to check the prototype for missing elements.
9656 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9657 int fast_length = static_cast<int>(length);
9658 ASSERT(fast_length <= elements->length());
9659 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009660 HandleScope loop_scope(isolate);
9661 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009662 if (!element_value->IsTheHole()) {
9663 visitor->visit(j, element_value);
9664 } else if (receiver->HasElement(j)) {
9665 // Call GetElement on receiver, not its prototype, or getters won't
9666 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009667 element_value = Object::GetElement(receiver, j);
9668 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009669 visitor->visit(j, element_value);
9670 }
9671 }
9672 break;
9673 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009674 case FAST_DOUBLE_ELEMENTS: {
9675 // TODO(1810): Decide if it's worthwhile to implement this.
9676 UNREACHABLE();
9677 break;
9678 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009679 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009680 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009681 List<uint32_t> indices(dict->Capacity() / 2);
9682 // Collect all indices in the object and the prototypes less
9683 // than length. This might introduce duplicates in the indices list.
9684 CollectElementIndices(receiver, length, &indices);
9685 indices.Sort(&compareUInt32);
9686 int j = 0;
9687 int n = indices.length();
9688 while (j < n) {
9689 HandleScope loop_scope;
9690 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009691 Handle<Object> element = Object::GetElement(receiver, index);
9692 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009693 visitor->visit(index, element);
9694 // Skip to next different index (i.e., omit duplicates).
9695 do {
9696 j++;
9697 } while (j < n && indices[j] == index);
9698 }
9699 break;
9700 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009701 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009702 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9703 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009704 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009705 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009706 visitor->visit(j, e);
9707 }
9708 break;
9709 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009710 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009711 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009712 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009713 break;
9714 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009715 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009716 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009717 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009718 break;
9719 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009720 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009721 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009722 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009723 break;
9724 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009725 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009726 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009727 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009728 break;
9729 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009730 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009731 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009732 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009733 break;
9734 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009735 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009736 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009737 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009738 break;
9739 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009740 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009741 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009742 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009743 break;
9744 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009745 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009746 IterateExternalArrayElements<ExternalDoubleArray, double>(
9747 isolate, receiver, false, false, visitor);
9748 break;
9749 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009750 default:
9751 UNREACHABLE();
9752 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009753 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009754 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009755 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009756}
9757
9758
9759/**
9760 * Array::concat implementation.
9761 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009762 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009763 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009764 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009765RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009766 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009767 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009768
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009769 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009770 int argument_count = static_cast<int>(arguments->length()->Number());
9771 RUNTIME_ASSERT(arguments->HasFastElements());
9772 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009773
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009774 // Pass 1: estimate the length and number of elements of the result.
9775 // The actual length can be larger if any of the arguments have getters
9776 // that mutate other arguments (but will otherwise be precise).
9777 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009778
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009779 uint32_t estimate_result_length = 0;
9780 uint32_t estimate_nof_elements = 0;
9781 {
9782 for (int i = 0; i < argument_count; i++) {
9783 HandleScope loop_scope;
9784 Handle<Object> obj(elements->get(i));
9785 uint32_t length_estimate;
9786 uint32_t element_estimate;
9787 if (obj->IsJSArray()) {
9788 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009789 // TODO(1810): Find out if it's worthwhile to properly support
9790 // arbitrary ElementsKinds. For now, pessimistically transition to
9791 // FAST_ELEMENTS.
9792 if (array->HasFastDoubleElements()) {
9793 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009794 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009795 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009796 length_estimate =
9797 static_cast<uint32_t>(array->length()->Number());
9798 element_estimate =
9799 EstimateElementCount(array);
9800 } else {
9801 length_estimate = 1;
9802 element_estimate = 1;
9803 }
9804 // Avoid overflows by capping at kMaxElementCount.
9805 if (JSObject::kMaxElementCount - estimate_result_length <
9806 length_estimate) {
9807 estimate_result_length = JSObject::kMaxElementCount;
9808 } else {
9809 estimate_result_length += length_estimate;
9810 }
9811 if (JSObject::kMaxElementCount - estimate_nof_elements <
9812 element_estimate) {
9813 estimate_nof_elements = JSObject::kMaxElementCount;
9814 } else {
9815 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009816 }
9817 }
9818 }
9819
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009820 // If estimated number of elements is more than half of length, a
9821 // fixed array (fast case) is more time and space-efficient than a
9822 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009823 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009824
9825 Handle<FixedArray> storage;
9826 if (fast_case) {
9827 // The backing storage array must have non-existing elements to
9828 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009829 storage = isolate->factory()->NewFixedArrayWithHoles(
9830 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009831 } else {
9832 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9833 uint32_t at_least_space_for = estimate_nof_elements +
9834 (estimate_nof_elements >> 2);
9835 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009836 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009837 }
9838
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009839 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009840
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009841 for (int i = 0; i < argument_count; i++) {
9842 Handle<Object> obj(elements->get(i));
9843 if (obj->IsJSArray()) {
9844 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009845 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009846 return Failure::Exception();
9847 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009848 } else {
9849 visitor.visit(0, obj);
9850 visitor.increase_index_offset(1);
9851 }
9852 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009853
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009854 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009855}
9856
9857
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009858// This will not allocate (flatten the string), but it may run
9859// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009860RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009861 NoHandleAllocation ha;
9862 ASSERT(args.length() == 1);
9863
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009864 CONVERT_ARG_CHECKED(String, string, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009865 StringInputBuffer buffer(string);
9866 while (buffer.has_more()) {
9867 uint16_t character = buffer.GetNext();
9868 PrintF("%c", character);
9869 }
9870 return string;
9871}
9872
ager@chromium.org5ec48922009-05-05 07:25:34 +00009873// Moves all own elements of an object, that are below a limit, to positions
9874// starting at zero. All undefined values are placed after non-undefined values,
9875// and are followed by non-existing element. Does not change the length
9876// property.
9877// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009878RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009879 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009880 CONVERT_ARG_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009881 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9882 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009883}
9884
9885
9886// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009887RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009888 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009889 CONVERT_ARG_CHECKED(JSArray, from, 0);
9890 CONVERT_ARG_CHECKED(JSArray, to, 1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009891 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009892 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009893 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009894 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9895 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009896 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009897 } else if (new_elements->map() ==
9898 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009899 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009900 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009901 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009902 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009903 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009904 Object* new_map;
9905 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009906 to->set_map(Map::cast(new_map));
9907 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009908 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009909 Object* obj;
9910 { MaybeObject* maybe_obj = from->ResetElements();
9911 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9912 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009913 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009914 return to;
9915}
9916
9917
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009918// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009919RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009920 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009921 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009922 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009923 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009924 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
9925 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009926 } else if (object->IsJSArray()) {
9927 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009928 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009929 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009930 }
9931}
9932
9933
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009934RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009935 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009936
9937 ASSERT_EQ(3, args.length());
9938
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009939 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009940 Handle<Object> key1 = args.at<Object>(1);
9941 Handle<Object> key2 = args.at<Object>(2);
9942
9943 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009944 if (!key1->ToArrayIndex(&index1)
9945 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009946 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009947 }
9948
ager@chromium.orgac091b72010-05-05 07:34:42 +00009949 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009950 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009951 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009952 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009953 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009954
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009955 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009956 isolate, JSObject::SetElement(jsobject, index1, tmp2, NONE, kStrictMode));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009957 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009958 isolate, JSObject::SetElement(jsobject, index2, tmp1, NONE, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009959
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009960 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009961}
9962
9963
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009964// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009965// might have elements. Can either return keys (positive integers) or
9966// intervals (pair of a negative integer (-start-1) followed by a
9967// positive (length)) or undefined values.
9968// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009969RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009970 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009971 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009972 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009973 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009974 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009975 // Create an array and get all the keys into it, then remove all the
9976 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009977 bool threw = false;
9978 Handle<FixedArray> keys =
9979 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
9980 if (threw) return Failure::Exception();
9981
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009982 int keys_length = keys->length();
9983 for (int i = 0; i < keys_length; i++) {
9984 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009985 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009986 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009987 // Zap invalid keys.
9988 keys->set_undefined(i);
9989 }
9990 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009991 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009992 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009993 ASSERT(array->HasFastElements() ||
9994 array->HasFastSmiOnlyElements() ||
9995 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009996 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009997 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009998 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009999 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010000 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010001 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010002 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010003 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010004 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010005 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010006 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010007 }
10008}
10009
10010
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010011RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010012 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010013 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10014 CONVERT_ARG_CHECKED(String, name, 1);
10015 CONVERT_SMI_ARG_CHECKED(flag, 2);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000010016 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
10017 return obj->LookupAccessor(name, component);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010018}
10019
10020
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010021#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010022RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010023 ASSERT(args.length() == 0);
10024 return Execution::DebugBreakHelper();
10025}
10026
10027
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010028// Helper functions for wrapping and unwrapping stack frame ids.
10029static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010030 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010031 return Smi::FromInt(id >> 2);
10032}
10033
10034
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010035static StackFrame::Id UnwrapFrameId(int wrapped) {
10036 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010037}
10038
10039
10040// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010041// args[0]: debug event listener function to set or null or undefined for
10042// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010043// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010044RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010045 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010046 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10047 args[0]->IsUndefined() ||
10048 args[0]->IsNull());
10049 Handle<Object> callback = args.at<Object>(0);
10050 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010051 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010052
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010053 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010054}
10055
10056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010057RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010058 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010059 isolate->stack_guard()->DebugBreak();
10060 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010061}
10062
10063
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010064static MaybeObject* DebugLookupResultValue(Heap* heap,
10065 Object* receiver,
10066 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010067 LookupResult* result,
10068 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010069 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010070 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010071 case NORMAL:
10072 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010073 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010074 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010075 }
10076 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010077 case FIELD:
10078 value =
10079 JSObject::cast(
10080 result->holder())->FastPropertyAt(result->GetFieldIndex());
10081 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010082 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010083 }
10084 return value;
10085 case CONSTANT_FUNCTION:
10086 return result->GetConstantFunction();
10087 case CALLBACKS: {
10088 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010089 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010090 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10091 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010092 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010093 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010094 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010095 maybe_value = heap->isolate()->pending_exception();
10096 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010097 if (caught_exception != NULL) {
10098 *caught_exception = true;
10099 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010100 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010101 }
10102 return value;
10103 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010104 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010105 }
10106 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010107 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010108 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010109 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010110 case CONSTANT_TRANSITION:
10111 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010112 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010113 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010114 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010115 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010116 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010117 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010118 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010119}
10120
10121
ager@chromium.org32912102009-01-16 10:38:43 +000010122// Get debugger related details for an object property.
10123// args[0]: object holding property
10124// args[1]: name of the property
10125//
10126// The array returned contains the following information:
10127// 0: Property value
10128// 1: Property details
10129// 2: Property value is exception
10130// 3: Getter function if defined
10131// 4: Setter function if defined
10132// Items 2-4 are only filled if the property has either a getter or a setter
10133// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010134RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010135 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010136
10137 ASSERT(args.length() == 2);
10138
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010139 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10140 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010141
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010142 // Make sure to set the current context to the context before the debugger was
10143 // entered (if the debugger is entered). The reason for switching context here
10144 // is that for some property lookups (accessors and interceptors) callbacks
10145 // into the embedding application can occour, and the embedding application
10146 // could have the assumption that its own global context is the current
10147 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010148 SaveContext save(isolate);
10149 if (isolate->debug()->InDebugger()) {
10150 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010151 }
10152
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010153 // Skip the global proxy as it has no properties and always delegates to the
10154 // real global object.
10155 if (obj->IsJSGlobalProxy()) {
10156 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10157 }
10158
10159
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010160 // Check if the name is trivially convertible to an index and get the element
10161 // if so.
10162 uint32_t index;
10163 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010164 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010165 Object* element_or_char;
10166 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010167 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010168 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10169 return maybe_element_or_char;
10170 }
10171 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010172 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010173 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010174 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010175 }
10176
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010177 // Find the number of objects making up this.
10178 int length = LocalPrototypeChainLength(*obj);
10179
10180 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010181 Handle<JSObject> jsproto = obj;
10182 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010183 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010184 jsproto->LocalLookup(*name, &result);
10185 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010186 // LookupResult is not GC safe as it holds raw object pointers.
10187 // GC can happen later in this code so put the required fields into
10188 // local variables using handles when required for later use.
10189 PropertyType result_type = result.type();
10190 Handle<Object> result_callback_obj;
10191 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010192 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10193 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010194 }
10195 Smi* property_details = result.GetPropertyDetails().AsSmi();
10196 // DebugLookupResultValue can cause GC so details from LookupResult needs
10197 // to be copied to handles before this.
10198 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010199 Object* raw_value;
10200 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010201 DebugLookupResultValue(isolate->heap(), *obj, *name,
10202 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010203 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10204 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010205 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010206
10207 // If the callback object is a fixed array then it contains JavaScript
10208 // getter and/or setter.
10209 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010210 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010211 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010212 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010213 details->set(0, *value);
10214 details->set(1, property_details);
10215 if (hasJavaScriptAccessors) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010216 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010217 details->set(2, isolate->heap()->ToBoolean(caught_exception));
danno@chromium.org88aa0582012-03-23 15:11:57 +000010218 details->set(3, accessors->GetComponent(ACCESSOR_GETTER));
10219 details->set(4, accessors->GetComponent(ACCESSOR_SETTER));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010220 }
10221
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010222 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010223 }
10224 if (i < length - 1) {
10225 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10226 }
10227 }
10228
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010229 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010230}
10231
10232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010233RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010234 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010235
10236 ASSERT(args.length() == 2);
10237
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010238 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10239 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010240
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010241 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010242 obj->Lookup(*name, &result);
10243 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010244 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010246 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010247}
10248
10249
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010250// Return the property type calculated from the property details.
10251// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010252RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010253 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010254 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10255 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010256}
10257
10258
10259// Return the property attribute calculated from the property details.
10260// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010261RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010262 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010263 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10264 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010265}
10266
10267
10268// Return the property insertion index calculated from the property details.
10269// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010270RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010271 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010272 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10273 return Smi::FromInt(details.index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010274}
10275
10276
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010277// Return property value from named interceptor.
10278// args[0]: object
10279// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010280RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010281 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010282 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010283 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010284 RUNTIME_ASSERT(obj->HasNamedInterceptor());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010285 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010286
10287 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010288 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010289}
10290
10291
10292// Return element value from indexed interceptor.
10293// args[0]: object
10294// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010295RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010296 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010297 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010298 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010299 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10300 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10301
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010302 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010303}
10304
10305
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010306RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010307 ASSERT(args.length() >= 1);
10308 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010309 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010310 if (isolate->debug()->break_id() == 0 ||
10311 break_id != isolate->debug()->break_id()) {
10312 return isolate->Throw(
10313 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010314 }
10315
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010316 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010317}
10318
10319
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010320RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010321 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010322 ASSERT(args.length() == 1);
10323
10324 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010325 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010326 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10327 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010328 if (!maybe_result->ToObject(&result)) return maybe_result;
10329 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010330
10331 // Count all frames which are relevant to debugging stack trace.
10332 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010333 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010334 if (id == StackFrame::NO_ID) {
10335 // If there is no JavaScript stack frame count is 0.
10336 return Smi::FromInt(0);
10337 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010338
10339 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10340 n += it.frame()->GetInlineCount();
10341 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010342 return Smi::FromInt(n);
10343}
10344
10345
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010346class FrameInspector {
10347 public:
10348 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010349 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010350 Isolate* isolate)
10351 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10352 // Calculate the deoptimized frame.
10353 if (frame->is_optimized()) {
10354 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010355 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010356 }
10357 has_adapted_arguments_ = frame_->has_adapted_arguments();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010358 is_bottommost_ = inlined_jsframe_index == 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010359 is_optimized_ = frame_->is_optimized();
10360 }
10361
10362 ~FrameInspector() {
10363 // Get rid of the calculated deoptimized frame if any.
10364 if (deoptimized_frame_ != NULL) {
10365 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10366 isolate_);
10367 }
10368 }
10369
10370 int GetParametersCount() {
10371 return is_optimized_
10372 ? deoptimized_frame_->parameters_count()
10373 : frame_->ComputeParametersCount();
10374 }
10375 int expression_count() { return deoptimized_frame_->expression_count(); }
10376 Object* GetFunction() {
10377 return is_optimized_
10378 ? deoptimized_frame_->GetFunction()
10379 : frame_->function();
10380 }
10381 Object* GetParameter(int index) {
10382 return is_optimized_
10383 ? deoptimized_frame_->GetParameter(index)
10384 : frame_->GetParameter(index);
10385 }
10386 Object* GetExpression(int index) {
10387 return is_optimized_
10388 ? deoptimized_frame_->GetExpression(index)
10389 : frame_->GetExpression(index);
10390 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010391 int GetSourcePosition() {
10392 return is_optimized_
10393 ? deoptimized_frame_->GetSourcePosition()
10394 : frame_->LookupCode()->SourcePosition(frame_->pc());
10395 }
ulan@chromium.org967e2702012-02-28 09:49:15 +000010396 bool IsConstructor() {
10397 return is_optimized_ && !is_bottommost_
10398 ? deoptimized_frame_->HasConstructStub()
10399 : frame_->IsConstructor();
10400 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010401
10402 // To inspect all the provided arguments the frame might need to be
10403 // replaced with the arguments frame.
10404 void SetArgumentsFrame(JavaScriptFrame* frame) {
10405 ASSERT(has_adapted_arguments_);
10406 frame_ = frame;
10407 is_optimized_ = frame_->is_optimized();
10408 ASSERT(!is_optimized_);
10409 }
10410
10411 private:
10412 JavaScriptFrame* frame_;
10413 DeoptimizedFrameInfo* deoptimized_frame_;
10414 Isolate* isolate_;
10415 bool is_optimized_;
ulan@chromium.org967e2702012-02-28 09:49:15 +000010416 bool is_bottommost_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010417 bool has_adapted_arguments_;
10418
10419 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10420};
10421
10422
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010423static const int kFrameDetailsFrameIdIndex = 0;
10424static const int kFrameDetailsReceiverIndex = 1;
10425static const int kFrameDetailsFunctionIndex = 2;
10426static const int kFrameDetailsArgumentCountIndex = 3;
10427static const int kFrameDetailsLocalCountIndex = 4;
10428static const int kFrameDetailsSourcePositionIndex = 5;
10429static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010430static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010431static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010432static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010433
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010434
10435static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10436 JavaScriptFrame* frame) {
10437 SaveContext* save = isolate->save_context();
10438 while (save != NULL && !save->IsBelowFrame(frame)) {
10439 save = save->prev();
10440 }
10441 ASSERT(save != NULL);
10442 return save;
10443}
10444
10445
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010446// Return an array with frame details
10447// args[0]: number: break id
10448// args[1]: number: frame index
10449//
10450// The array returned contains the following information:
10451// 0: Frame id
10452// 1: Receiver
10453// 2: Function
10454// 3: Argument count
10455// 4: Local count
10456// 5: Source position
10457// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010458// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010459// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010460// Arguments name, value
10461// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010462// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010463RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010464 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010465 ASSERT(args.length() == 2);
10466
10467 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010468 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010469 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10470 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010471 if (!maybe_check->ToObject(&check)) return maybe_check;
10472 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010473 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010474 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010475
10476 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010477 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010478 if (id == StackFrame::NO_ID) {
10479 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010480 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010481 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010482
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010483 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010484 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010485 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010486 if (index < count + it.frame()->GetInlineCount()) break;
10487 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010488 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010489 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010490
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010491 bool is_optimized = it.frame()->is_optimized();
10492
10493 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10494 if (is_optimized) {
10495 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010496 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010497 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010498 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010499
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010500 // Traverse the saved contexts chain to find the active context for the
10501 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010502 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010503
10504 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010505 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010506
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010507 // Find source position in unoptimized code.
10508 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010509
ulan@chromium.org967e2702012-02-28 09:49:15 +000010510 // Check for constructor frame.
10511 bool constructor = frame_inspector.IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010512
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010513 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010514 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010515 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010516 Handle<ScopeInfo> scope_info(shared->scope_info());
10517 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010518
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010519 // Get the locals names and values into a temporary array.
10520 //
10521 // TODO(1240907): Hide compiler-introduced stack variables
10522 // (e.g. .result)? For users of the debugger, they will probably be
10523 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010524 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010525 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010526
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010527 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010528 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010529 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010530 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010531 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010532 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010533 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010534 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010535 // Get the context containing declarations.
10536 Handle<Context> context(
10537 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010538 for (; i < scope_info->LocalCount(); ++i) {
10539 Handle<String> name(scope_info->LocalName(i));
10540 VariableMode mode;
10541 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010542 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010543 locals->set(i * 2 + 1, context->get(
10544 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010545 }
10546 }
10547
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010548 // Check whether this frame is positioned at return. If not top
10549 // frame or if the frame is optimized it cannot be at a return.
10550 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010551 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010552 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010553 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010554
10555 // If positioned just before return find the value to be returned and add it
10556 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010557 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010558 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010559 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010560 Address internal_frame_sp = NULL;
10561 while (!it2.done()) {
10562 if (it2.frame()->is_internal()) {
10563 internal_frame_sp = it2.frame()->sp();
10564 } else {
10565 if (it2.frame()->is_java_script()) {
10566 if (it2.frame()->id() == it.frame()->id()) {
10567 // The internal frame just before the JavaScript frame contains the
10568 // value to return on top. A debug break at return will create an
10569 // internal frame to store the return value (eax/rax/r0) before
10570 // entering the debug break exit frame.
10571 if (internal_frame_sp != NULL) {
10572 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010573 Handle<Object>(Memory::Object_at(internal_frame_sp),
10574 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010575 break;
10576 }
10577 }
10578 }
10579
10580 // Indicate that the previous frame was not an internal frame.
10581 internal_frame_sp = NULL;
10582 }
10583 it2.Advance();
10584 }
10585 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010586
10587 // Now advance to the arguments adapter frame (if any). It contains all
10588 // the provided parameters whereas the function frame always have the number
10589 // of arguments matching the functions parameters. The rest of the
10590 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010591 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010592 it.AdvanceToArgumentsFrame();
10593 frame_inspector.SetArgumentsFrame(it.frame());
10594 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010595
10596 // Find the number of arguments to fill. At least fill the number of
10597 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010598 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010599 if (argument_count < frame_inspector.GetParametersCount()) {
10600 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010601 }
10602
10603 // Calculate the size of the result.
10604 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010605 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010606 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010607 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010608
10609 // Add the frame id.
10610 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10611
10612 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010613 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010614
10615 // Add the arguments count.
10616 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10617
10618 // Add the locals count
10619 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010620 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010621
10622 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010623 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010624 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10625 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010626 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010627 }
10628
10629 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010630 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010631
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010632 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010633 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010634
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010635 // Add flags to indicate information on whether this frame is
10636 // bit 0: invoked in the debugger context.
10637 // bit 1: optimized frame.
10638 // bit 2: inlined in optimized frame
10639 int flags = 0;
10640 if (*save->context() == *isolate->debug()->debug_context()) {
10641 flags |= 1 << 0;
10642 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010643 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010644 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010645 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010646 }
10647 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010648
10649 // Fill the dynamic part.
10650 int details_index = kFrameDetailsFirstDynamicIndex;
10651
10652 // Add arguments name and value.
10653 for (int i = 0; i < argument_count; i++) {
10654 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010655 if (i < scope_info->ParameterCount()) {
10656 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010657 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010658 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010659 }
10660
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010661 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010662 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010663 // Get the value from the stack.
10664 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010665 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010666 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010667 }
10668 }
10669
10670 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010671 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010672 details->set(details_index++, locals->get(i));
10673 }
10674
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010675 // Add the value being returned.
10676 if (at_return) {
10677 details->set(details_index++, *return_value);
10678 }
10679
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010680 // Add the receiver (same as in function frame).
10681 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10682 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010683 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010684 if (!receiver->IsJSObject() &&
10685 shared->is_classic_mode() &&
10686 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010687 // If the receiver is not a JSObject and the function is not a
10688 // builtin or strict-mode we have hit an optimization where a
10689 // value object is not converted into a wrapped JS objects. To
10690 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010691 // by creating correct wrapper object based on the calling frame's
10692 // global context.
10693 it.Advance();
10694 Handle<Context> calling_frames_global_context(
10695 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010696 receiver =
10697 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010698 }
10699 details->set(kFrameDetailsReceiverIndex, *receiver);
10700
10701 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010702 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010703}
10704
10705
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010706// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010707static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010708 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010709 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010710 Handle<Context> context,
10711 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010712 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010713 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
10714 VariableMode mode;
10715 InitializationFlag init_flag;
10716 int context_index = scope_info->ContextSlotIndex(
10717 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010718
whesse@chromium.org7b260152011-06-20 15:33:18 +000010719 RETURN_IF_EMPTY_HANDLE_VALUE(
10720 isolate,
10721 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010722 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000010723 Handle<Object>(context->get(context_index), isolate),
10724 NONE,
10725 kNonStrictMode),
10726 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010727 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010728
10729 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010730}
10731
10732
10733// Create a plain JSObject which materializes the local scope for the specified
10734// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010735static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010736 Isolate* isolate,
10737 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010738 FrameInspector* frame_inspector) {
10739 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010740 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010741 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010742
10743 // Allocate and initialize a JSObject with all the arguments, stack locals
10744 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010745 Handle<JSObject> local_scope =
10746 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010747
10748 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010749 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010750 Handle<Object> value(
10751 i < frame_inspector->GetParametersCount() ?
10752 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
10753
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010754 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010755 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010756 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010757 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010758 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010759 NONE,
10760 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010761 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010762 }
10763
10764 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010765 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010766 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010767 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010768 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010769 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010770 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010771 NONE,
10772 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010773 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010774 }
10775
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010776 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010777 // Third fill all context locals.
10778 Handle<Context> frame_context(Context::cast(frame->context()));
10779 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010780 if (!CopyContextLocalsToScopeObject(
10781 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010782 return Handle<JSObject>();
10783 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010784
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010785 // Finally copy any properties from the function context extension.
10786 // These will be variables introduced by eval.
10787 if (function_context->closure() == *function) {
10788 if (function_context->has_extension() &&
10789 !function_context->IsGlobalContext()) {
10790 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010791 bool threw = false;
10792 Handle<FixedArray> keys =
10793 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10794 if (threw) return Handle<JSObject>();
10795
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010796 for (int i = 0; i < keys->length(); i++) {
10797 // Names of variables introduced by eval are strings.
10798 ASSERT(keys->get(i)->IsString());
10799 Handle<String> key(String::cast(keys->get(i)));
10800 RETURN_IF_EMPTY_HANDLE_VALUE(
10801 isolate,
10802 SetProperty(local_scope,
10803 key,
10804 GetProperty(ext, key),
10805 NONE,
10806 kNonStrictMode),
10807 Handle<JSObject>());
10808 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010809 }
10810 }
10811 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010812
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010813 return local_scope;
10814}
10815
10816
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010817static Handle<JSObject> MaterializeLocalScope(
10818 Isolate* isolate,
10819 JavaScriptFrame* frame,
10820 int inlined_jsframe_index) {
10821 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
10822 return MaterializeLocalScopeWithFrameInspector(isolate,
10823 frame,
10824 &frame_inspector);
10825}
10826
10827
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010828// Create a plain JSObject which materializes the closure content for the
10829// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010830static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10831 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010832 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010833
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010834 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010835 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010836
ulan@chromium.org2efb9002012-01-19 15:36:35 +000010837 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010838 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010839 Handle<JSObject> closure_scope =
10840 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010841
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010842 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010843 if (!CopyContextLocalsToScopeObject(
10844 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010845 return Handle<JSObject>();
10846 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010847
10848 // Finally copy any properties from the function context extension. This will
10849 // be variables introduced by eval.
10850 if (context->has_extension()) {
10851 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010852 bool threw = false;
10853 Handle<FixedArray> keys =
10854 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10855 if (threw) return Handle<JSObject>();
10856
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010857 for (int i = 0; i < keys->length(); i++) {
10858 // Names of variables introduced by eval are strings.
10859 ASSERT(keys->get(i)->IsString());
10860 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010861 RETURN_IF_EMPTY_HANDLE_VALUE(
10862 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010863 SetProperty(closure_scope,
10864 key,
10865 GetProperty(ext, key),
10866 NONE,
10867 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010868 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010869 }
10870 }
10871
10872 return closure_scope;
10873}
10874
10875
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010876// Create a plain JSObject which materializes the scope for the specified
10877// catch context.
10878static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10879 Handle<Context> context) {
10880 ASSERT(context->IsCatchContext());
10881 Handle<String> name(String::cast(context->extension()));
10882 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10883 Handle<JSObject> catch_scope =
10884 isolate->factory()->NewJSObject(isolate->object_function());
10885 RETURN_IF_EMPTY_HANDLE_VALUE(
10886 isolate,
10887 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10888 Handle<JSObject>());
10889 return catch_scope;
10890}
10891
10892
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010893// Create a plain JSObject which materializes the block scope for the specified
10894// block context.
10895static Handle<JSObject> MaterializeBlockScope(
10896 Isolate* isolate,
10897 Handle<Context> context) {
10898 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010899 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010900
10901 // Allocate and initialize a JSObject with all the arguments, stack locals
10902 // heap locals and extension properties of the debugged function.
10903 Handle<JSObject> block_scope =
10904 isolate->factory()->NewJSObject(isolate->object_function());
10905
10906 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010907 if (!CopyContextLocalsToScopeObject(
10908 isolate, scope_info, context, block_scope)) {
10909 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010910 }
10911
10912 return block_scope;
10913}
10914
10915
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010916// Create a plain JSObject which materializes the module scope for the specified
10917// module context.
10918static Handle<JSObject> MaterializeModuleScope(
10919 Isolate* isolate,
10920 Handle<Context> context) {
10921 ASSERT(context->IsModuleContext());
10922 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
10923
10924 // Allocate and initialize a JSObject with all the members of the debugged
10925 // module.
10926 Handle<JSObject> module_scope =
10927 isolate->factory()->NewJSObject(isolate->object_function());
10928
10929 // Fill all context locals.
10930 if (!CopyContextLocalsToScopeObject(
10931 isolate, scope_info, context, module_scope)) {
10932 return Handle<JSObject>();
10933 }
10934
10935 return module_scope;
10936}
10937
10938
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010939// Iterate over the actual scopes visible from a stack frame. The iteration
10940// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010941// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010942// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010943class ScopeIterator {
10944 public:
10945 enum ScopeType {
10946 ScopeTypeGlobal = 0,
10947 ScopeTypeLocal,
10948 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010949 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010950 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010951 ScopeTypeBlock,
10952 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010953 };
10954
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010955 ScopeIterator(Isolate* isolate,
10956 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010957 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010958 : isolate_(isolate),
10959 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010960 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010961 function_(JSFunction::cast(frame->function())),
10962 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010963 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010964
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010965 // Catch the case when the debugger stops in an internal function.
10966 Handle<SharedFunctionInfo> shared_info(function_->shared());
10967 Handle<ScopeInfo> scope_info(shared_info->scope_info());
10968 if (shared_info->script() == isolate->heap()->undefined_value()) {
10969 while (context_->closure() == *function_) {
10970 context_ = Handle<Context>(context_->previous(), isolate_);
10971 }
10972 return;
10973 }
10974
10975 // Get the debug info (create it if it does not exist).
10976 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
10977 // Return if ensuring debug info failed.
10978 return;
10979 }
10980 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
10981
10982 // Find the break point where execution has stopped.
10983 BreakLocationIterator break_location_iterator(debug_info,
10984 ALL_BREAK_LOCATIONS);
10985 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
10986 if (break_location_iterator.IsExit()) {
10987 // We are within the return sequence. At the momemt it is not possible to
10988 // get a source position which is consistent with the current scope chain.
10989 // Thus all nested with, catch and block contexts are skipped and we only
10990 // provide the function scope.
10991 if (scope_info->HasContext()) {
10992 context_ = Handle<Context>(context_->declaration_context(), isolate_);
10993 } else {
10994 while (context_->closure() == *function_) {
10995 context_ = Handle<Context>(context_->previous(), isolate_);
10996 }
10997 }
10998 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
10999 } else {
11000 // Reparse the code and analyze the scopes.
11001 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11002 Handle<Script> script(Script::cast(shared_info->script()));
11003 Scope* scope = NULL;
11004
11005 // Check whether we are in global, eval or function code.
11006 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11007 if (scope_info->Type() != FUNCTION_SCOPE) {
11008 // Global or eval code.
11009 CompilationInfo info(script);
11010 if (scope_info->Type() == GLOBAL_SCOPE) {
11011 info.MarkAsGlobal();
11012 } else {
11013 ASSERT(scope_info->Type() == EVAL_SCOPE);
11014 info.MarkAsEval();
11015 info.SetCallingContext(Handle<Context>(function_->context()));
11016 }
11017 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11018 scope = info.function()->scope();
11019 }
11020 } else {
11021 // Function code
11022 CompilationInfo info(shared_info);
11023 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11024 scope = info.function()->scope();
11025 }
11026 }
11027
11028 // Retrieve the scope chain for the current position.
11029 if (scope != NULL) {
11030 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11031 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11032 } else {
11033 // A failed reparse indicates that the preparser has diverged from the
11034 // parser or that the preparse data given to the initial parse has been
11035 // faulty. We fail in debug mode but in release mode we only provide the
11036 // information we get from the context chain but nothing about
11037 // completely stack allocated scopes or stack allocated locals.
11038 UNREACHABLE();
11039 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011040 }
11041 }
11042
11043 // More scopes?
11044 bool Done() { return context_.is_null(); }
11045
11046 // Move to the next scope.
11047 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011048 ScopeType scope_type = Type();
11049 if (scope_type == ScopeTypeGlobal) {
11050 // The global scope is always the last in the chain.
11051 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011052 context_ = Handle<Context>();
11053 return;
11054 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011055 if (nested_scope_chain_.is_empty()) {
11056 context_ = Handle<Context>(context_->previous(), isolate_);
11057 } else {
11058 if (nested_scope_chain_.last()->HasContext()) {
11059 ASSERT(context_->previous() != NULL);
11060 context_ = Handle<Context>(context_->previous(), isolate_);
11061 }
11062 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011063 }
11064 }
11065
11066 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011067 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011068 if (!nested_scope_chain_.is_empty()) {
11069 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11070 switch (scope_info->Type()) {
11071 case FUNCTION_SCOPE:
11072 ASSERT(context_->IsFunctionContext() ||
11073 !scope_info->HasContext());
11074 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011075 case MODULE_SCOPE:
11076 ASSERT(context_->IsModuleContext());
11077 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011078 case GLOBAL_SCOPE:
11079 ASSERT(context_->IsGlobalContext());
11080 return ScopeTypeGlobal;
11081 case WITH_SCOPE:
11082 ASSERT(context_->IsWithContext());
11083 return ScopeTypeWith;
11084 case CATCH_SCOPE:
11085 ASSERT(context_->IsCatchContext());
11086 return ScopeTypeCatch;
11087 case BLOCK_SCOPE:
11088 ASSERT(!scope_info->HasContext() ||
11089 context_->IsBlockContext());
11090 return ScopeTypeBlock;
11091 case EVAL_SCOPE:
11092 UNREACHABLE();
11093 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011094 }
11095 if (context_->IsGlobalContext()) {
11096 ASSERT(context_->global()->IsGlobalObject());
11097 return ScopeTypeGlobal;
11098 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011099 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011100 return ScopeTypeClosure;
11101 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011102 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011103 return ScopeTypeCatch;
11104 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011105 if (context_->IsBlockContext()) {
11106 return ScopeTypeBlock;
11107 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011108 if (context_->IsModuleContext()) {
11109 return ScopeTypeModule;
11110 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011111 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011112 return ScopeTypeWith;
11113 }
11114
11115 // Return the JavaScript object with the content of the current scope.
11116 Handle<JSObject> ScopeObject() {
11117 switch (Type()) {
11118 case ScopeIterator::ScopeTypeGlobal:
11119 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011120 case ScopeIterator::ScopeTypeLocal:
11121 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011122 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011123 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011124 case ScopeIterator::ScopeTypeWith:
11125 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011126 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11127 case ScopeIterator::ScopeTypeCatch:
11128 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011129 case ScopeIterator::ScopeTypeClosure:
11130 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011131 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011132 case ScopeIterator::ScopeTypeBlock:
11133 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011134 case ScopeIterator::ScopeTypeModule:
11135 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011136 }
11137 UNREACHABLE();
11138 return Handle<JSObject>();
11139 }
11140
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011141 Handle<ScopeInfo> CurrentScopeInfo() {
11142 if (!nested_scope_chain_.is_empty()) {
11143 return nested_scope_chain_.last();
11144 } else if (context_->IsBlockContext()) {
11145 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11146 } else if (context_->IsFunctionContext()) {
11147 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11148 }
11149 return Handle<ScopeInfo>::null();
11150 }
11151
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011152 // Return the context for this scope. For the local context there might not
11153 // be an actual context.
11154 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011155 if (Type() == ScopeTypeGlobal ||
11156 nested_scope_chain_.is_empty()) {
11157 return context_;
11158 } else if (nested_scope_chain_.last()->HasContext()) {
11159 return context_;
11160 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011161 return Handle<Context>();
11162 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011163 }
11164
11165#ifdef DEBUG
11166 // Debug print of the content of the current scope.
11167 void DebugPrint() {
11168 switch (Type()) {
11169 case ScopeIterator::ScopeTypeGlobal:
11170 PrintF("Global:\n");
11171 CurrentContext()->Print();
11172 break;
11173
11174 case ScopeIterator::ScopeTypeLocal: {
11175 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011176 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011177 if (!CurrentContext().is_null()) {
11178 CurrentContext()->Print();
11179 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011180 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011181 if (extension->IsJSContextExtensionObject()) {
11182 extension->Print();
11183 }
11184 }
11185 }
11186 break;
11187 }
11188
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011189 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011190 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011191 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011192 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011193
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011194 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011195 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011196 CurrentContext()->extension()->Print();
11197 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011198 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011199
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011200 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011201 PrintF("Closure:\n");
11202 CurrentContext()->Print();
11203 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011204 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011205 if (extension->IsJSContextExtensionObject()) {
11206 extension->Print();
11207 }
11208 }
11209 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011210
11211 default:
11212 UNREACHABLE();
11213 }
11214 PrintF("\n");
11215 }
11216#endif
11217
11218 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011219 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011220 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011221 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011222 Handle<JSFunction> function_;
11223 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011224 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011225
11226 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11227};
11228
11229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011230RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011231 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011232 ASSERT(args.length() == 2);
11233
11234 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011235 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011236 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11237 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011238 if (!maybe_check->ToObject(&check)) return maybe_check;
11239 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011240 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011241
11242 // Get the frame where the debugging is performed.
11243 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011244 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011245 JavaScriptFrame* frame = it.frame();
11246
11247 // Count the visible scopes.
11248 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011249 for (ScopeIterator it(isolate, frame, 0);
11250 !it.Done();
11251 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011252 n++;
11253 }
11254
11255 return Smi::FromInt(n);
11256}
11257
11258
11259static const int kScopeDetailsTypeIndex = 0;
11260static const int kScopeDetailsObjectIndex = 1;
11261static const int kScopeDetailsSize = 2;
11262
11263// Return an array with scope details
11264// args[0]: number: break id
11265// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011266// args[2]: number: inlined frame index
11267// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011268//
11269// The array returned contains the following information:
11270// 0: Scope type
11271// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011272RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011273 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011274 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011275
11276 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011277 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011278 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11279 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011280 if (!maybe_check->ToObject(&check)) return maybe_check;
11281 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011282 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011283 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011284 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011285
11286 // Get the frame where the debugging is performed.
11287 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011288 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011289 JavaScriptFrame* frame = frame_it.frame();
11290
11291 // Find the requested scope.
11292 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011293 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011294 for (; !it.Done() && n < index; it.Next()) {
11295 n++;
11296 }
11297 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011298 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011299 }
11300
11301 // Calculate the size of the result.
11302 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011303 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011304
11305 // Fill in scope details.
11306 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011307 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011308 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011309 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011311 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011312}
11313
11314
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011315RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011316 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011317 ASSERT(args.length() == 0);
11318
11319#ifdef DEBUG
11320 // Print the scopes for the top frame.
11321 StackFrameLocator locator;
11322 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011323 for (ScopeIterator it(isolate, frame, 0);
11324 !it.Done();
11325 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011326 it.DebugPrint();
11327 }
11328#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011329 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011330}
11331
11332
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011333RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011334 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011335 ASSERT(args.length() == 1);
11336
11337 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011338 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011339 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11340 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011341 if (!maybe_result->ToObject(&result)) return maybe_result;
11342 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011343
11344 // Count all archived V8 threads.
11345 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011346 for (ThreadState* thread =
11347 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011348 thread != NULL;
11349 thread = thread->Next()) {
11350 n++;
11351 }
11352
11353 // Total number of threads is current thread and archived threads.
11354 return Smi::FromInt(n + 1);
11355}
11356
11357
11358static const int kThreadDetailsCurrentThreadIndex = 0;
11359static const int kThreadDetailsThreadIdIndex = 1;
11360static const int kThreadDetailsSize = 2;
11361
11362// Return an array with thread details
11363// args[0]: number: break id
11364// args[1]: number: thread index
11365//
11366// The array returned contains the following information:
11367// 0: Is current thread?
11368// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011369RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011370 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011371 ASSERT(args.length() == 2);
11372
11373 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011374 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011375 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11376 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011377 if (!maybe_check->ToObject(&check)) return maybe_check;
11378 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011379 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11380
11381 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011382 Handle<FixedArray> details =
11383 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011384
11385 // Thread index 0 is current thread.
11386 if (index == 0) {
11387 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011388 details->set(kThreadDetailsCurrentThreadIndex,
11389 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011390 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011391 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011392 } else {
11393 // Find the thread with the requested index.
11394 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011395 ThreadState* thread =
11396 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011397 while (index != n && thread != NULL) {
11398 thread = thread->Next();
11399 n++;
11400 }
11401 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011402 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011403 }
11404
11405 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011406 details->set(kThreadDetailsCurrentThreadIndex,
11407 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011408 details->set(kThreadDetailsThreadIdIndex,
11409 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011410 }
11411
11412 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011413 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011414}
11415
11416
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011417// Sets the disable break state
11418// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011419RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011420 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011421 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011422 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011423 isolate->debug()->set_disable_break(disable_break);
11424 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011425}
11426
11427
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011428RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011429 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011430 ASSERT(args.length() == 1);
11431
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011432 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011433 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011434 // Find the number of break points
11435 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011436 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011437 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011438 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011439 Handle<FixedArray>::cast(break_locations));
11440}
11441
11442
11443// Set a break point in a function
11444// args[0]: function
11445// args[1]: number: break source position (within the function source)
11446// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011447RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011448 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011449 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011450 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011451 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011452 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11453 RUNTIME_ASSERT(source_position >= 0);
11454 Handle<Object> break_point_object_arg = args.at<Object>(2);
11455
11456 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011457 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11458 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011459
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011460 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011461}
11462
11463
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011464Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11465 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011466 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011467 // Iterate the heap looking for SharedFunctionInfo generated from the
11468 // script. The inner most SharedFunctionInfo containing the source position
11469 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011470 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011471 // which is found is not compiled it is compiled and the heap is iterated
11472 // again as the compilation might create inner functions from the newly
11473 // compiled function and the actual requested break point might be in one of
11474 // these functions.
11475 bool done = false;
11476 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011477 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011478 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011479 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011480 { // Extra scope for iterator and no-allocation.
11481 isolate->heap()->EnsureHeapIsIterable();
11482 AssertNoAllocation no_alloc_during_heap_iteration;
11483 HeapIterator iterator;
11484 for (HeapObject* obj = iterator.next();
11485 obj != NULL; obj = iterator.next()) {
11486 if (obj->IsSharedFunctionInfo()) {
11487 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11488 if (shared->script() == *script) {
11489 // If the SharedFunctionInfo found has the requested script data and
11490 // contains the source position it is a candidate.
11491 int start_position = shared->function_token_position();
11492 if (start_position == RelocInfo::kNoPosition) {
11493 start_position = shared->start_position();
11494 }
11495 if (start_position <= position &&
11496 position <= shared->end_position()) {
11497 // If there is no candidate or this function is within the current
11498 // candidate this is the new candidate.
11499 if (target.is_null()) {
11500 target_start_position = start_position;
11501 target = shared;
11502 } else {
11503 if (target_start_position == start_position &&
11504 shared->end_position() == target->end_position()) {
11505 // If a top-level function contain only one function
11506 // declartion the source for the top-level and the
11507 // function is the same. In that case prefer the non
11508 // top-level function.
11509 if (!shared->is_toplevel()) {
11510 target_start_position = start_position;
11511 target = shared;
11512 }
11513 } else if (target_start_position <= start_position &&
11514 shared->end_position() <= target->end_position()) {
11515 // This containment check includes equality as a function
11516 // inside a top-level function can share either start or end
11517 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011518 target_start_position = start_position;
11519 target = shared;
11520 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011521 }
11522 }
11523 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011524 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011525 } // End for loop.
11526 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011527
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011528 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011529 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011530 }
11531
11532 // If the candidate found is compiled we are done. NOTE: when lazy
11533 // compilation of inner functions is introduced some additional checking
11534 // needs to be done here to compile inner functions.
11535 done = target->is_compiled();
11536 if (!done) {
11537 // If the candidate is not compiled compile it to reveal any inner
11538 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011539 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011540 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011541 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011542
11543 return *target;
11544}
11545
11546
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011547// Changes the state of a break point in a script and returns source position
11548// where break point was set. NOTE: Regarding performance see the NOTE for
11549// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011550// args[0]: script to set break point in
11551// args[1]: number: break source position (within the script source)
11552// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011553RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011554 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011555 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011556 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011557 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11558 RUNTIME_ASSERT(source_position >= 0);
11559 Handle<Object> break_point_object_arg = args.at<Object>(2);
11560
11561 // Get the script from the script wrapper.
11562 RUNTIME_ASSERT(wrapper->value()->IsScript());
11563 Handle<Script> script(Script::cast(wrapper->value()));
11564
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011565 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011566 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011567 if (!result->IsUndefined()) {
11568 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11569 // Find position within function. The script position might be before the
11570 // source position of the first function.
11571 int position;
11572 if (shared->start_position() > source_position) {
11573 position = 0;
11574 } else {
11575 position = source_position - shared->start_position();
11576 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011577 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011578 position += shared->start_position();
11579 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011580 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011581 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011582}
11583
11584
11585// Clear a break point
11586// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011587RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011588 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011589 ASSERT(args.length() == 1);
11590 Handle<Object> break_point_object_arg = args.at<Object>(0);
11591
11592 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011593 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011594
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011595 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011596}
11597
11598
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011599// Change the state of break on exceptions.
11600// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11601// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011602RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011603 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011604 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011605 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011606 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011607
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011608 // If the number doesn't match an enum value, the ChangeBreakOnException
11609 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011610 ExceptionBreakType type =
11611 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011612 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011613 isolate->debug()->ChangeBreakOnException(type, enable);
11614 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011615}
11616
11617
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011618// Returns the state of break on exceptions
11619// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011620RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011621 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011622 ASSERT(args.length() == 1);
11623 RUNTIME_ASSERT(args[0]->IsNumber());
11624
11625 ExceptionBreakType type =
11626 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011627 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011628 return Smi::FromInt(result);
11629}
11630
11631
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011632// Prepare for stepping
11633// args[0]: break id for checking execution state
11634// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011635// args[2]: number of times to perform the step, for step out it is the number
11636// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011637RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011638 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011639 ASSERT(args.length() == 3);
11640 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011641 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011642 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11643 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011644 if (!maybe_check->ToObject(&check)) return maybe_check;
11645 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011646 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011647 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011648 }
11649
11650 // Get the step action and check validity.
11651 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11652 if (step_action != StepIn &&
11653 step_action != StepNext &&
11654 step_action != StepOut &&
11655 step_action != StepInMin &&
11656 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011657 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011658 }
11659
11660 // Get the number of steps.
11661 int step_count = NumberToInt32(args[2]);
11662 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011663 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011664 }
11665
ager@chromium.orga1645e22009-09-09 19:27:10 +000011666 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011667 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011668
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011669 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011670 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11671 step_count);
11672 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011673}
11674
11675
11676// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011677RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011678 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011679 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011680 isolate->debug()->ClearStepping();
11681 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011682}
11683
11684
11685// Creates a copy of the with context chain. The copy of the context chain is
11686// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011687static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11688 Handle<JSFunction> function,
11689 Handle<Context> base,
11690 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011691 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011692 HandleScope scope(isolate);
11693 List<Handle<ScopeInfo> > scope_chain;
11694 List<Handle<Context> > context_chain;
11695
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011696 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011697 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11698 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11699 ASSERT(!it.Done());
11700 scope_chain.Add(it.CurrentScopeInfo());
11701 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011702 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011703
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011704 // At the end of the chain. Return the base context to link to.
11705 Handle<Context> context = base;
11706
11707 // Iteratively copy and or materialize the nested contexts.
11708 while (!scope_chain.is_empty()) {
11709 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11710 Handle<Context> current = context_chain.RemoveLast();
11711 ASSERT(!(scope_info->HasContext() & current.is_null()));
11712
11713 if (scope_info->Type() == CATCH_SCOPE) {
11714 Handle<String> name(String::cast(current->extension()));
11715 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11716 context =
11717 isolate->factory()->NewCatchContext(function,
11718 context,
11719 name,
11720 thrown_object);
11721 } else if (scope_info->Type() == BLOCK_SCOPE) {
11722 // Materialize the contents of the block scope into a JSObject.
11723 Handle<JSObject> block_scope_object =
11724 MaterializeBlockScope(isolate, current);
11725 if (block_scope_object.is_null()) {
11726 return Handle<Context>::null();
11727 }
11728 // Allocate a new function context for the debug evaluation and set the
11729 // extension object.
11730 Handle<Context> new_context =
11731 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11732 function);
11733 new_context->set_extension(*block_scope_object);
11734 new_context->set_previous(*context);
11735 context = new_context;
11736 } else {
11737 ASSERT(scope_info->Type() == WITH_SCOPE);
11738 ASSERT(current->IsWithContext());
11739 Handle<JSObject> extension(JSObject::cast(current->extension()));
11740 context =
11741 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000011742 }
erikcorry0ad885c2011-11-21 13:51:57 +000011743 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011744
11745 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011746}
11747
11748
11749// Helper function to find or create the arguments object for
11750// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011751static Handle<Object> GetArgumentsObject(Isolate* isolate,
11752 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011753 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011754 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011755 Handle<Context> function_context) {
11756 // Try to find the value of 'arguments' to pass as parameter. If it is not
11757 // found (that is the debugged function does not reference 'arguments' and
11758 // does not support eval) then create an 'arguments' object.
11759 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011760 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011761 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011762 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011763 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011764 }
11765 }
11766
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011767 if (scope_info->HasHeapAllocatedLocals()) {
11768 VariableMode mode;
11769 InitializationFlag init_flag;
11770 index = scope_info->ContextSlotIndex(
11771 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011772 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011773 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011774 }
11775 }
11776
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011777 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
11778 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011779 Handle<JSObject> arguments =
11780 isolate->factory()->NewArgumentsObject(function, length);
11781 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011782
11783 AssertNoAllocation no_gc;
11784 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011785 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011786 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011787 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011788 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011789 return arguments;
11790}
11791
11792
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011793static const char kSourceStr[] =
11794 "(function(arguments,__source__){return eval(__source__);})";
11795
11796
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011797// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011798// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011799// extension part has all the parameters and locals of the function on the
11800// stack frame. A function which calls eval with the code to evaluate is then
11801// compiled in this context and called in this context. As this context
11802// replaces the context of the function on the stack frame a new (empty)
11803// function is created as well to be used as the closure for the context.
11804// This function and the context acts as replacements for the function on the
11805// stack frame presenting the same view of the values of parameters and
11806// local variables as if the piece of JavaScript was evaluated at the point
11807// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011808RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011809 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011810
11811 // Check the execution state and decode arguments frame and source to be
11812 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011813 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011814 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011815 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11816 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011817 if (!maybe_check_result->ToObject(&check_result)) {
11818 return maybe_check_result;
11819 }
11820 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011821 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011822 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011823 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
11824 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011825 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011826
11827 // Handle the processing of break.
11828 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011829
11830 // Get the frame where the debugging is performed.
11831 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011832 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011833 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011834 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11835 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011836 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011837
11838 // Traverse the saved contexts chain to find the active context for the
11839 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011840 SaveContext* save = FindSavedContextForFrame(isolate, frame);
11841
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011842 SaveContext savex(isolate);
11843 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011844
11845 // Create the (empty) function replacing the function on the stack frame for
11846 // the purpose of evaluating in the context created below. It is important
11847 // that this function does not describe any parameters and local variables
11848 // in the context. If it does then this will cause problems with the lookup
11849 // in Context::Lookup, where context slots for parameters and local variables
11850 // are looked at before the extension object.
11851 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011852 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11853 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011854 go_between->set_context(function->context());
11855#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011856 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
11857 ASSERT(go_between_scope_info->ParameterCount() == 0);
11858 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011859#endif
11860
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011861 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011862 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
11863 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011864 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011865
11866 // Allocate a new context for the debug evaluation and set the extension
11867 // object build.
11868 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011869 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11870 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011871 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011872 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011873 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011874 Handle<Context> function_context;
11875 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011876 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011877 function_context = Handle<Context>(frame_context->declaration_context());
11878 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011879 context = CopyNestedScopeContextChain(isolate,
11880 go_between,
11881 context,
11882 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011883 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011884
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011885 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011886 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011887 context =
11888 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011889 }
11890
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011891 // Wrap the evaluation statement in a new function compiled in the newly
11892 // created context. The function has one parameter which has to be called
11893 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011894 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011895 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011896
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011897 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011898 isolate->factory()->NewStringFromAscii(
11899 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011900
11901 // Currently, the eval code will be executed in non-strict mode,
11902 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011903 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011904 Compiler::CompileEval(function_source,
11905 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011906 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011907 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011908 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011909 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011910 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011911 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011912
11913 // Invoke the result of the compilation to get the evaluation function.
11914 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011915 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011916 Handle<Object> evaluation_function =
11917 Execution::Call(compiled_function, receiver, 0, NULL,
11918 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011919 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011920
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011921 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011922 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011923 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011924 scope_info,
11925 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011926
11927 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011928 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011929 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011930 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
11931 receiver,
11932 ARRAY_SIZE(argv),
11933 argv,
11934 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011935 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011936
11937 // Skip the global proxy as it has no properties and always delegates to the
11938 // real global object.
11939 if (result->IsJSGlobalProxy()) {
11940 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11941 }
11942
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011943 return *result;
11944}
11945
11946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011947RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011948 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011949
11950 // Check the execution state and decode arguments frame and source to be
11951 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011952 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011953 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011954 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11955 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011956 if (!maybe_check_result->ToObject(&check_result)) {
11957 return maybe_check_result;
11958 }
11959 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011960 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
11961 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011962 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011963
11964 // Handle the processing of break.
11965 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011966
11967 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011968 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011969 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011970 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011971 top = top->prev();
11972 }
11973 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011974 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011975 }
11976
11977 // Get the global context now set to the top context from before the
11978 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011979 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011980
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011981 bool is_global = true;
11982
11983 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000011984 // Create a new with context with the additional context information between
11985 // the context of the debugged function and the eval code to be executed.
11986 context = isolate->factory()->NewWithContext(
11987 Handle<JSFunction>(context->closure()),
11988 context,
11989 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011990 is_global = false;
11991 }
11992
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011993 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011994 // Currently, the eval code will be executed in non-strict mode,
11995 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011996 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011997 Compiler::CompileEval(source,
11998 context,
11999 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012000 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012001 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012002 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012003 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012004 Handle<JSFunction>(
12005 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12006 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012007
12008 // Invoke the result of the compilation to get the evaluation function.
12009 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012010 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012011 Handle<Object> result =
12012 Execution::Call(compiled_function, receiver, 0, NULL,
12013 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012014 // Clear the oneshot breakpoints so that the debugger does not step further.
12015 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012016 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012017 return *result;
12018}
12019
12020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012021RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012022 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012023 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012024
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012025 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012026 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012027
12028 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012029 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012030 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12031 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12032 // because using
12033 // instances->set(i, *GetScriptWrapper(script))
12034 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012035 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012036 Handle<JSValue> wrapper = GetScriptWrapper(script);
12037 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012038 }
12039
12040 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012041 Handle<JSObject> result =
12042 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012043 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012044 return *result;
12045}
12046
12047
12048// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012049static int DebugReferencedBy(HeapIterator* iterator,
12050 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012051 Object* instance_filter, int max_references,
12052 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012053 JSFunction* arguments_function) {
12054 NoHandleAllocation ha;
12055 AssertNoAllocation no_alloc;
12056
12057 // Iterate the heap.
12058 int count = 0;
12059 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012060 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012061 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012062 (max_references == 0 || count < max_references)) {
12063 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012064 if (heap_obj->IsJSObject()) {
12065 // Skip context extension objects and argument arrays as these are
12066 // checked in the context of functions using them.
12067 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012068 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012069 obj->map()->constructor() == arguments_function) {
12070 continue;
12071 }
12072
12073 // Check if the JS object has a reference to the object looked for.
12074 if (obj->ReferencesObject(target)) {
12075 // Check instance filter if supplied. This is normally used to avoid
12076 // references from mirror objects (see Runtime_IsInPrototypeChain).
12077 if (!instance_filter->IsUndefined()) {
12078 Object* V = obj;
12079 while (true) {
12080 Object* prototype = V->GetPrototype();
12081 if (prototype->IsNull()) {
12082 break;
12083 }
12084 if (instance_filter == prototype) {
12085 obj = NULL; // Don't add this object.
12086 break;
12087 }
12088 V = prototype;
12089 }
12090 }
12091
12092 if (obj != NULL) {
12093 // Valid reference found add to instance array if supplied an update
12094 // count.
12095 if (instances != NULL && count < instances_size) {
12096 instances->set(count, obj);
12097 }
12098 last = obj;
12099 count++;
12100 }
12101 }
12102 }
12103 }
12104
12105 // Check for circular reference only. This can happen when the object is only
12106 // referenced from mirrors and has a circular reference in which case the
12107 // object is not really alive and would have been garbage collected if not
12108 // referenced from the mirror.
12109 if (count == 1 && last == target) {
12110 count = 0;
12111 }
12112
12113 // Return the number of referencing objects found.
12114 return count;
12115}
12116
12117
12118// Scan the heap for objects with direct references to an object
12119// args[0]: the object to find references to
12120// args[1]: constructor function for instances to exclude (Mirror)
12121// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012122RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012123 ASSERT(args.length() == 3);
12124
12125 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012126 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12127 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012128 // The heap iterator reserves the right to do a GC to make the heap iterable.
12129 // Due to the GC above we know it won't need to do that, but it seems cleaner
12130 // to get the heap iterator constructed before we start having unprotected
12131 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012132
12133 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012134 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012135 Object* instance_filter = args[1];
12136 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12137 instance_filter->IsJSObject());
12138 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12139 RUNTIME_ASSERT(max_references >= 0);
12140
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012141
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012142 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012143 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012144 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012145 JSFunction* arguments_function =
12146 JSFunction::cast(arguments_boilerplate->map()->constructor());
12147
12148 // Get the number of referencing objects.
12149 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012150 HeapIterator heap_iterator;
12151 count = DebugReferencedBy(&heap_iterator,
12152 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012153 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012154
12155 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012156 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012157 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012158 if (!maybe_object->ToObject(&object)) return maybe_object;
12159 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012160 FixedArray* instances = FixedArray::cast(object);
12161
12162 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012163 // AllocateFixedArray above does not make the heap non-iterable.
12164 ASSERT(HEAP->IsHeapIterable());
12165 HeapIterator heap_iterator2;
12166 count = DebugReferencedBy(&heap_iterator2,
12167 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012168 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012169
12170 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012171 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012172 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012173 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012174 if (!maybe_result->ToObject(&result)) return maybe_result;
12175 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012176}
12177
12178
12179// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012180static int DebugConstructedBy(HeapIterator* iterator,
12181 JSFunction* constructor,
12182 int max_references,
12183 FixedArray* instances,
12184 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012185 AssertNoAllocation no_alloc;
12186
12187 // Iterate the heap.
12188 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012189 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012190 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012191 (max_references == 0 || count < max_references)) {
12192 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012193 if (heap_obj->IsJSObject()) {
12194 JSObject* obj = JSObject::cast(heap_obj);
12195 if (obj->map()->constructor() == constructor) {
12196 // Valid reference found add to instance array if supplied an update
12197 // count.
12198 if (instances != NULL && count < instances_size) {
12199 instances->set(count, obj);
12200 }
12201 count++;
12202 }
12203 }
12204 }
12205
12206 // Return the number of referencing objects found.
12207 return count;
12208}
12209
12210
12211// Scan the heap for objects constructed by a specific function.
12212// args[0]: the constructor to find instances of
12213// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012214RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012215 ASSERT(args.length() == 2);
12216
12217 // First perform a full GC in order to avoid dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012218 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12219 "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012220
12221 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012222 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012223 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12224 RUNTIME_ASSERT(max_references >= 0);
12225
12226 // Get the number of referencing objects.
12227 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012228 HeapIterator heap_iterator;
12229 count = DebugConstructedBy(&heap_iterator,
12230 constructor,
12231 max_references,
12232 NULL,
12233 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012234
12235 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012236 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012237 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012238 if (!maybe_object->ToObject(&object)) return maybe_object;
12239 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012240 FixedArray* instances = FixedArray::cast(object);
12241
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012242 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012243 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012244 HeapIterator heap_iterator2;
12245 count = DebugConstructedBy(&heap_iterator2,
12246 constructor,
12247 max_references,
12248 instances,
12249 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012250
12251 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012252 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012253 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12254 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012255 if (!maybe_result->ToObject(&result)) return maybe_result;
12256 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012257 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012258}
12259
12260
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012261// Find the effective prototype object as returned by __proto__.
12262// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012263RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012264 ASSERT(args.length() == 1);
12265
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012266 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012267
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012268 // Use the __proto__ accessor.
12269 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012270}
12271
12272
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000012273// Patches script source (should be called upon BeforeCompile event).
12274RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) {
12275 HandleScope scope(isolate);
12276 ASSERT(args.length() == 2);
12277
12278 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
12279 Handle<String> source(String::cast(args[1]));
12280
12281 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
12282 Handle<Script> script(Script::cast(script_wrapper->value()));
12283
12284 int compilation_state = Smi::cast(script->compilation_state())->value();
12285 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
12286 script->set_source(*source);
12287
12288 return isolate->heap()->undefined_value();
12289}
12290
12291
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012292RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012293 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012294 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012295 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012296}
12297
12298
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012299RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012300#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012301 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012302 ASSERT(args.length() == 1);
12303 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012304 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012305 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012306 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012307 return Failure::Exception();
12308 }
12309 func->code()->PrintLn();
12310#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012311 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012312}
ager@chromium.org9085a012009-05-11 19:22:57 +000012313
12314
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012315RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012316#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012317 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012318 ASSERT(args.length() == 1);
12319 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012320 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012321 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012322 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012323 return Failure::Exception();
12324 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012325 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012326#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012327 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012328}
12329
12330
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012331RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012332 NoHandleAllocation ha;
12333 ASSERT(args.length() == 1);
12334
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012335 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000012336 return f->shared()->inferred_name();
12337}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012338
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012339
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012340static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12341 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012342 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012343 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012344 int counter = 0;
12345 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012346 for (HeapObject* obj = iterator->next();
12347 obj != NULL;
12348 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012349 ASSERT(obj != NULL);
12350 if (!obj->IsSharedFunctionInfo()) {
12351 continue;
12352 }
12353 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12354 if (shared->script() != script) {
12355 continue;
12356 }
12357 if (counter < buffer_size) {
12358 buffer->set(counter, shared);
12359 }
12360 counter++;
12361 }
12362 return counter;
12363}
12364
12365// For a script finds all SharedFunctionInfo's in the heap that points
12366// to this script. Returns JSArray of SharedFunctionInfo wrapped
12367// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012368RUNTIME_FUNCTION(MaybeObject*,
12369 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012370 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012371 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012372 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012373
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012374
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012375 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12376
12377 const int kBufferSize = 32;
12378
12379 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012380 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012381 int number;
12382 {
12383 isolate->heap()->EnsureHeapIsIterable();
12384 AssertNoAllocation no_allocations;
12385 HeapIterator heap_iterator;
12386 Script* scr = *script;
12387 FixedArray* arr = *array;
12388 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12389 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012390 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012391 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012392 isolate->heap()->EnsureHeapIsIterable();
12393 AssertNoAllocation no_allocations;
12394 HeapIterator heap_iterator;
12395 Script* scr = *script;
12396 FixedArray* arr = *array;
12397 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012398 }
12399
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012400 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012401 result->set_length(Smi::FromInt(number));
12402
12403 LiveEdit::WrapSharedFunctionInfos(result);
12404
12405 return *result;
12406}
12407
12408// For a script calculates compilation information about all its functions.
12409// The script source is explicitly specified by the second argument.
12410// The source of the actual script is not used, however it is important that
12411// all generated code keeps references to this particular instance of script.
12412// Returns a JSArray of compilation infos. The array is ordered so that
12413// each function with all its descendant is always stored in a continues range
12414// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012415RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012416 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012417 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012418 CONVERT_ARG_CHECKED(JSValue, script, 0);
12419 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012420 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12421
12422 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12423
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012424 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012425 return Failure::Exception();
12426 }
12427
12428 return result;
12429}
12430
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012431// Changes the source of the script to a new_source.
12432// If old_script_name is provided (i.e. is a String), also creates a copy of
12433// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012434RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012435 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012436 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012437 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
12438 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012439 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012440
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012441 RUNTIME_ASSERT(original_script_value->value()->IsScript());
12442 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012443
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012444 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12445 new_source,
12446 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012447
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012448 if (old_script->IsScript()) {
12449 Handle<Script> script_handle(Script::cast(old_script));
12450 return *(GetScriptWrapper(script_handle));
12451 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012452 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012453 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012454}
12455
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012456
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012457RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012458 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012459 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012460 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012461 return LiveEdit::FunctionSourceUpdated(shared_info);
12462}
12463
12464
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012465// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012466RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012467 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012468 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012469 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
12470 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012471
ager@chromium.orgac091b72010-05-05 07:34:42 +000012472 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012473}
12474
12475// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012476RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012477 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012478 HandleScope scope(isolate);
12479 Handle<Object> function_object(args[0], isolate);
12480 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012481
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012482 if (function_object->IsJSValue()) {
12483 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12484 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012485 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
12486 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012487 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012488 }
12489
12490 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12491 } else {
12492 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12493 // and we check it in this function.
12494 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012495
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012496 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012497}
12498
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012499
12500// In a code of a parent function replaces original function as embedded object
12501// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012502RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012503 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012504 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012505
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012506 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
12507 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
12508 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012509
12510 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12511 subst_wrapper);
12512
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012513 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012514}
12515
12516
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012517// Updates positions of a shared function info (first parameter) according
12518// to script source change. Text change is described in second parameter as
12519// array of groups of 3 numbers:
12520// (change_begin, change_end, change_end_new_position).
12521// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012522RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012523 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012524 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012525 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12526 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012527
ager@chromium.orgac091b72010-05-05 07:34:42 +000012528 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012529}
12530
12531
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012532// For array of SharedFunctionInfo's (each wrapped in JSValue)
12533// checks that none of them have activations on stacks (of any thread).
12534// Returns array of the same length with corresponding results of
12535// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012536RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012537 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012538 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012539 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12540 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012541
ager@chromium.org357bf652010-04-12 11:30:10 +000012542 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012543}
12544
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012545// Compares 2 strings line-by-line, then token-wise and returns diff in form
12546// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12547// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012548RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012549 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012550 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012551 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
12552 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012553
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012554 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012555}
12556
12557
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012558// A testing entry. Returns statement position which is the closest to
12559// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012560RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012561 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012562 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012563 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012564 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12565
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012566 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012567
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012568 if (code->kind() != Code::FUNCTION &&
12569 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012570 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012571 }
12572
12573 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012574 int closest_pc = 0;
12575 int distance = kMaxInt;
12576 while (!it.done()) {
12577 int statement_position = static_cast<int>(it.rinfo()->data());
12578 // Check if this break point is closer that what was previously found.
12579 if (source_position <= statement_position &&
12580 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012581 closest_pc =
12582 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012583 distance = statement_position - source_position;
12584 // Check whether we can't get any closer.
12585 if (distance == 0) break;
12586 }
12587 it.next();
12588 }
12589
12590 return Smi::FromInt(closest_pc);
12591}
12592
12593
ager@chromium.org357bf652010-04-12 11:30:10 +000012594// Calls specified function with or without entering the debugger.
12595// This is used in unit tests to run code as if debugger is entered or simply
12596// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012597RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012598 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012599 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012600 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12601 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000012602
12603 Handle<Object> result;
12604 bool pending_exception;
12605 {
12606 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012607 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012608 &pending_exception);
12609 } else {
12610 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012611 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012612 &pending_exception);
12613 }
12614 }
12615 if (!pending_exception) {
12616 return *result;
12617 } else {
12618 return Failure::Exception();
12619 }
12620}
12621
12622
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012623// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012624RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012625 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012626 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012627 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12628 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012629 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012630}
12631
12632
12633// Performs a GC.
12634// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012635RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000012636 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012637 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012638}
12639
12640
12641// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012642RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012643 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012644 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012645 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012646 }
12647 return Smi::FromInt(usage);
12648}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012649
12650
12651// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012652RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012653#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012654 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012655#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012656 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012657#endif
12658}
12659
12660
12661// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012662RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012663#ifdef LIVE_OBJECT_LIST
12664 return LiveObjectList::Capture();
12665#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012666 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012667#endif
12668}
12669
12670
12671// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012672RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012673#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012674 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012675 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012676 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012677#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012678 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012679#endif
12680}
12681
12682
12683// Generates the response to a debugger request for a dump of the objects
12684// contained in the difference between the captured live object lists
12685// specified by id1 and id2.
12686// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12687// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012688RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012689#ifdef LIVE_OBJECT_LIST
12690 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012691 CONVERT_SMI_ARG_CHECKED(id1, 0);
12692 CONVERT_SMI_ARG_CHECKED(id2, 1);
12693 CONVERT_SMI_ARG_CHECKED(start, 2);
12694 CONVERT_SMI_ARG_CHECKED(count, 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012695 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012696 EnterDebugger enter_debugger;
12697 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12698#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012699 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012700#endif
12701}
12702
12703
12704// Gets the specified object as requested by the debugger.
12705// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012706RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012707#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012708 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012709 Object* result = LiveObjectList::GetObj(obj_id);
12710 return result;
12711#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012712 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012713#endif
12714}
12715
12716
12717// Gets the obj id for the specified address if valid.
12718// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012719RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012720#ifdef LIVE_OBJECT_LIST
12721 HandleScope scope;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012722 CONVERT_ARG_HANDLE_CHECKED(String, address, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012723 Object* result = LiveObjectList::GetObjId(address);
12724 return result;
12725#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012726 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012727#endif
12728}
12729
12730
12731// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012732RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012733#ifdef LIVE_OBJECT_LIST
12734 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012735 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012736 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12737 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12738 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12739 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012740 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012741
12742 Handle<JSObject> instance_filter;
12743 if (args[1]->IsJSObject()) {
12744 instance_filter = args.at<JSObject>(1);
12745 }
12746 bool verbose = false;
12747 if (args[2]->IsBoolean()) {
12748 verbose = args[2]->IsTrue();
12749 }
12750 int start = 0;
12751 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012752 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012753 }
12754 int limit = Smi::kMaxValue;
12755 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012756 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012757 }
12758
12759 return LiveObjectList::GetObjRetainers(obj_id,
12760 instance_filter,
12761 verbose,
12762 start,
12763 limit,
12764 filter_obj);
12765#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012766 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012767#endif
12768}
12769
12770
12771// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012772RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012773#ifdef LIVE_OBJECT_LIST
12774 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012775 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12776 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012777 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12778
12779 Handle<JSObject> instance_filter;
12780 if (args[2]->IsJSObject()) {
12781 instance_filter = args.at<JSObject>(2);
12782 }
12783
12784 Object* result =
12785 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12786 return result;
12787#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012788 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012789#endif
12790}
12791
12792
12793// Generates the response to a debugger request for a list of all
12794// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012795RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012796#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012797 CONVERT_SMI_ARG_CHECKED(start, 0);
12798 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012799 return LiveObjectList::Info(start, count);
12800#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012801 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012802#endif
12803}
12804
12805
12806// Gets a dump of the specified object as requested by the debugger.
12807// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012808RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012809#ifdef LIVE_OBJECT_LIST
12810 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012811 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012812 Object* result = LiveObjectList::PrintObj(obj_id);
12813 return result;
12814#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012815 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012816#endif
12817}
12818
12819
12820// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012821RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012822#ifdef LIVE_OBJECT_LIST
12823 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012824 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012825#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012826 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012827#endif
12828}
12829
12830
12831// Generates the response to a debugger request for a summary of the types
12832// of objects in the difference between the captured live object lists
12833// specified by id1 and id2.
12834// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12835// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012836RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012837#ifdef LIVE_OBJECT_LIST
12838 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012839 CONVERT_SMI_ARG_CHECKED(id1, 0);
12840 CONVERT_SMI_ARG_CHECKED(id2, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012841 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012842
12843 EnterDebugger enter_debugger;
12844 return LiveObjectList::Summarize(id1, id2, filter_obj);
12845#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012846 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012847#endif
12848}
12849
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012850#endif // ENABLE_DEBUGGER_SUPPORT
12851
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012852
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012853RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012854 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012855 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012856 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012857}
12858
12859
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012860RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012861 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012862 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012863 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012864}
12865
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012866
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012867// Finds the script object from the script data. NOTE: This operation uses
12868// heap traversal to find the function generated for the source position
12869// for the requested break point. For lazily compiled functions several heap
12870// traversals might be required rendering this operation as a rather slow
12871// operation. However for setting break points which is normally done through
12872// some kind of user interaction the performance is not crucial.
12873static Handle<Object> Runtime_GetScriptFromScriptName(
12874 Handle<String> script_name) {
12875 // Scan the heap for Script objects to find the script with the requested
12876 // script data.
12877 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012878 script_name->GetHeap()->EnsureHeapIsIterable();
12879 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012880 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012881 HeapObject* obj = NULL;
12882 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012883 // If a script is found check if it has the script data requested.
12884 if (obj->IsScript()) {
12885 if (Script::cast(obj)->name()->IsString()) {
12886 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12887 script = Handle<Script>(Script::cast(obj));
12888 }
12889 }
12890 }
12891 }
12892
12893 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012894 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012895
12896 // Return the script found.
12897 return GetScriptWrapper(script);
12898}
12899
12900
12901// Get the script object from script data. NOTE: Regarding performance
12902// see the NOTE for GetScriptFromScriptData.
12903// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012904RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012905 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012906
12907 ASSERT(args.length() == 1);
12908
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012909 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012910
12911 // Find the requested script.
12912 Handle<Object> result =
12913 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12914 return *result;
12915}
12916
12917
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012918// Determines whether the given stack frame should be displayed in
12919// a stack trace. The caller is the error constructor that asked
12920// for the stack trace to be collected. The first time a construct
12921// call to this function is encountered it is skipped. The seen_caller
12922// in/out parameter is used to remember if the caller has been seen
12923// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012924static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12925 Object* caller,
12926 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012927 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012928 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012929 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012930 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012931 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12932 Object* raw_fun = frame->function();
12933 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012934 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012935 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012936 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012937 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012938 *seen_caller = true;
12939 return false;
12940 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012941 // Skip all frames until we've seen the caller.
12942 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012943 // Also, skip non-visible built-in functions and any call with the builtins
12944 // object as receiver, so as to not reveal either the builtins object or
12945 // an internal function.
12946 // The --builtins-in-stack-traces command line flag allows including
12947 // internal call sites in the stack trace for debugging purposes.
12948 if (!FLAG_builtins_in_stack_traces) {
12949 JSFunction* fun = JSFunction::cast(raw_fun);
12950 if (frame->receiver()->IsJSBuiltinsObject() ||
12951 (fun->IsBuiltin() && !fun->shared()->native())) {
12952 return false;
12953 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012954 }
12955 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012956}
12957
12958
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012959// Collect the raw data for a stack trace. Returns an array of 4
12960// element segments each containing a receiver, function, code and
12961// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012962RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012963 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012964 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012965 Handle<Object> caller = args.at<Object>(1);
12966 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012967
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012968 HandleScope scope(isolate);
12969 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012970
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012971 limit = Max(limit, 0); // Ensure that limit is not negative.
12972 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012973 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012974 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012975
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012976 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012977 // If the caller parameter is a function we skip frames until we're
12978 // under it before starting to collect.
12979 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012980 int cursor = 0;
12981 int frames_seen = 0;
12982 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012983 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012984 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012985 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012986 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012987 // Set initial size to the maximum inlining level + 1 for the outermost
12988 // function.
12989 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012990 frame->Summarize(&frames);
12991 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012992 if (cursor + 4 > elements->length()) {
12993 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12994 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012995 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012996 for (int i = 0; i < cursor; i++) {
12997 new_elements->set(i, elements->get(i));
12998 }
12999 elements = new_elements;
13000 }
13001 ASSERT(cursor + 4 <= elements->length());
13002
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013003 Handle<Object> recv = frames[i].receiver();
13004 Handle<JSFunction> fun = frames[i].function();
13005 Handle<Code> code = frames[i].code();
13006 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013007 elements->set(cursor++, *recv);
13008 elements->set(cursor++, *fun);
13009 elements->set(cursor++, *code);
13010 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013011 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013012 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013013 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013014 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013015 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013016 // Capture and attach a more detailed stack trace if necessary.
13017 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013018 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013019 return *result;
13020}
13021
13022
ager@chromium.org3811b432009-10-28 14:53:37 +000013023// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013024RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013025 ASSERT_EQ(args.length(), 0);
13026
13027 NoHandleAllocation ha;
13028
13029 const char* version_string = v8::V8::GetVersion();
13030
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013031 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13032 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013033}
13034
13035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013036RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013037 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013038 OS::PrintError("abort: %s\n",
13039 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013040 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013041 OS::Abort();
13042 UNREACHABLE();
13043 return NULL;
13044}
13045
13046
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013047RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013048 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013049 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013050 Object* key = args[1];
13051
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013052 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013053 Object* o = cache->get(finger_index);
13054 if (o == key) {
13055 // The fastest case: hit the same place again.
13056 return cache->get(finger_index + 1);
13057 }
13058
13059 for (int i = finger_index - 2;
13060 i >= JSFunctionResultCache::kEntriesIndex;
13061 i -= 2) {
13062 o = cache->get(i);
13063 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013064 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013065 return cache->get(i + 1);
13066 }
13067 }
13068
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013069 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013070 ASSERT(size <= cache->length());
13071
13072 for (int i = size - 2; i > finger_index; i -= 2) {
13073 o = cache->get(i);
13074 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013075 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013076 return cache->get(i + 1);
13077 }
13078 }
13079
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013080 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013081 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013082
13083 Handle<JSFunctionResultCache> cache_handle(cache);
13084 Handle<Object> key_handle(key);
13085 Handle<Object> value;
13086 {
13087 Handle<JSFunction> factory(JSFunction::cast(
13088 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13089 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013090 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013091 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013092 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013093 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013094 value = Execution::Call(factory,
13095 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013096 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013097 argv,
13098 &pending_exception);
13099 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013100 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013101
13102#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013103 if (FLAG_verify_heap) {
13104 cache_handle->JSFunctionResultCacheVerify();
13105 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013106#endif
13107
13108 // Function invocation may have cleared the cache. Reread all the data.
13109 finger_index = cache_handle->finger_index();
13110 size = cache_handle->size();
13111
13112 // If we have spare room, put new data into it, otherwise evict post finger
13113 // entry which is likely to be the least recently used.
13114 int index = -1;
13115 if (size < cache_handle->length()) {
13116 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13117 index = size;
13118 } else {
13119 index = finger_index + JSFunctionResultCache::kEntrySize;
13120 if (index == cache_handle->length()) {
13121 index = JSFunctionResultCache::kEntriesIndex;
13122 }
13123 }
13124
13125 ASSERT(index % 2 == 0);
13126 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13127 ASSERT(index < cache_handle->length());
13128
13129 cache_handle->set(index, *key_handle);
13130 cache_handle->set(index + 1, *value);
13131 cache_handle->set_finger_index(index);
13132
13133#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013134 if (FLAG_verify_heap) {
13135 cache_handle->JSFunctionResultCacheVerify();
13136 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013137#endif
13138
13139 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013140}
13141
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013142
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013143RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013144 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013145 CONVERT_ARG_HANDLE_CHECKED(String, type, 0);
13146 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013147 return *isolate->factory()->NewJSMessageObject(
13148 type,
13149 arguments,
13150 0,
13151 0,
13152 isolate->factory()->undefined_value(),
13153 isolate->factory()->undefined_value(),
13154 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013155}
13156
13157
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013158RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013159 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013160 return message->type();
13161}
13162
13163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013164RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013165 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013166 return message->arguments();
13167}
13168
13169
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013170RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013171 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013172 return Smi::FromInt(message->start_position());
13173}
13174
13175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013176RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013177 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013178 return message->script();
13179}
13180
13181
kasper.lund44510672008-07-25 07:37:58 +000013182#ifdef DEBUG
13183// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13184// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013185RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013186 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013187 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013188#define COUNT_ENTRY(Name, argc, ressize) + 1
13189 int entry_count = 0
13190 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13191 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13192 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13193#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013194 Factory* factory = isolate->factory();
13195 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013196 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013197 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013198#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013199 { \
13200 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013201 Handle<String> name; \
13202 /* Inline runtime functions have an underscore in front of the name. */ \
13203 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013204 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013205 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13206 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013207 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013208 Vector<const char>(#Name, StrLength(#Name))); \
13209 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013210 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013211 pair_elements->set(0, *name); \
13212 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013213 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013214 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013215 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013216 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013217 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013218 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013219 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013220 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013221#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013222 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013223 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013224 return *result;
13225}
kasper.lund44510672008-07-25 07:37:58 +000013226#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013227
13228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013229RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013230 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013231 CONVERT_ARG_CHECKED(String, format, 0);
13232 CONVERT_ARG_CHECKED(JSArray, elms, 1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013233 String::FlatContent format_content = format->GetFlatContent();
13234 RUNTIME_ASSERT(format_content.IsAscii());
13235 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013236 LOGGER->LogRuntime(chars, elms);
13237 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013238}
13239
13240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013241RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013242 UNREACHABLE(); // implemented as macro in the parser
13243 return NULL;
13244}
13245
13246
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013247#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13248 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013249 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013250 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13251 }
13252
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013253ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013254ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13255ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13256ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13257ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13258ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13259ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13260ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13261ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13262ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13263ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13264ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13265ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13266ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13267
13268#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13269
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013270
13271RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13272 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013273 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
13274 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013275 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13276}
13277
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013278// ----------------------------------------------------------------------------
13279// Implementation of Runtime
13280
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013281#define F(name, number_of_args, result_size) \
13282 { Runtime::k##name, Runtime::RUNTIME, #name, \
13283 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013284
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013285
13286#define I(name, number_of_args, result_size) \
13287 { Runtime::kInline##name, Runtime::INLINE, \
13288 "_" #name, NULL, number_of_args, result_size },
13289
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013290static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013291 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013292 INLINE_FUNCTION_LIST(I)
13293 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013294};
13295
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013296
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013297MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13298 Object* dictionary) {
13299 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013300 ASSERT(dictionary != NULL);
13301 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13302 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013303 Object* name_symbol;
13304 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013305 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013306 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13307 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013308 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013309 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13310 String::cast(name_symbol),
13311 Smi::FromInt(i),
13312 PropertyDetails(NONE, NORMAL));
13313 if (!maybe_dictionary->ToObject(&dictionary)) {
13314 // Non-recoverable failure. Calling code must restart heap
13315 // initialization.
13316 return maybe_dictionary;
13317 }
13318 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013319 }
13320 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013321}
13322
13323
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013324const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13325 Heap* heap = name->GetHeap();
13326 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013327 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013328 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013329 int function_index = Smi::cast(smi_index)->value();
13330 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013331 }
13332 return NULL;
13333}
13334
13335
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013336const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013337 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13338}
13339
13340
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013341void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013342 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013343 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013344 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013345 if (isolate->heap()->new_space()->AddFreshPage()) {
13346 return;
13347 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000013348
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013349 // Try to do a garbage collection; ignore it if it fails. The C
13350 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013351 isolate->heap()->CollectGarbage(failure->allocation_space(),
13352 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013353 } else {
13354 // Handle last resort GC and make sure to allow future allocations
13355 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013356 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013357 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13358 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013359 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013360}
13361
13362
13363} } // namespace v8::internal