blob: 34a47c5d00574cbf8eaf8d4c5a92edef4379f778 [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"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000047#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000050#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000051#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000056#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000059#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
ager@chromium.org3e875802009-06-29 08:26:34 +000066#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072#define CONVERT_ARG_CHECKED(Type, name, index) \
73 RUNTIME_ASSERT(args[index]->Is##Type()); \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000074 Type* name = Type::cast(args[index]);
75
76#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000078 Handle<Type> name = args.at<Type>(index);
79
kasper.lundbd3ec4e2008-07-09 11:06:54 +000080// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000083#define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
84 RUNTIME_ASSERT(args[index]->IsBoolean()); \
85 bool name = args[index]->IsTrue();
kasper.lundbd3ec4e2008-07-09 11:06:54 +000086
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000089// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000109// Cast the given argument to PropertyDetails and store its value in a
110// variable with the given name. If the argument is not a Smi call
111// IllegalOperation and return.
112#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
113 RUNTIME_ASSERT(args[index]->IsSmi()); \
114 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
115
116
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000117// Assert that the given argument has a valid value for a StrictModeFlag
118// and store it in a StrictModeFlag variable with the given name.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000119#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
120 RUNTIME_ASSERT(args[index]->IsSmi()); \
121 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
122 args.smi_at(index) == kNonStrictMode); \
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000123 StrictModeFlag name = \
124 static_cast<StrictModeFlag>(args.smi_at(index));
125
126
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000127// Assert that the given argument has a valid value for a LanguageMode
128// and store it in a LanguageMode variable with the given name.
129#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
130 ASSERT(args[index]->IsSmi()); \
131 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
132 args.smi_at(index) == STRICT_MODE || \
133 args.smi_at(index) == EXTENDED_MODE); \
134 LanguageMode name = \
135 static_cast<LanguageMode>(args.smi_at(index));
136
137
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000138MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
139 JSObject* boilerplate) {
140 StackLimitCheck check(isolate);
141 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000142
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000143 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000145 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000146 if (!maybe_result->ToObject(&result)) return maybe_result;
147 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000148 JSObject* copy = JSObject::cast(result);
149
150 // Deep copy local properties.
151 if (copy->HasFastProperties()) {
152 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 for (int i = 0; i < properties->length(); i++) {
154 Object* value = properties->get(i);
155 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000156 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000157 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000158 if (!maybe_result->ToObject(&result)) return maybe_result;
159 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000160 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000161 }
162 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000163 int nof = copy->map()->inobject_properties();
164 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000165 Object* value = copy->InObjectPropertyAt(i);
166 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000167 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000168 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000171 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000172 }
173 }
174 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000175 { MaybeObject* maybe_result =
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000176 heap->AllocateFixedArray(copy->NumberOfLocalProperties());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000177 if (!maybe_result->ToObject(&result)) return maybe_result;
178 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000179 FixedArray* names = FixedArray::cast(result);
180 copy->GetLocalPropertyNames(names, 0);
181 for (int i = 0; i < names->length(); i++) {
182 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000183 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000184 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000185 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000186 // Only deep copy fields from the object literal expression.
187 // In particular, don't try to copy the length attribute of
188 // an array.
189 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000190 Object* value =
191 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000192 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000193 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000194 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000195 if (!maybe_result->ToObject(&result)) return maybe_result;
196 }
197 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000198 // Creating object copy for literals. No strict mode needed.
199 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000200 if (!maybe_result->ToObject(&result)) return maybe_result;
201 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000202 }
203 }
204 }
205
206 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000207 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000208 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000209 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000210 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000211 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000212 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000213 if (elements->map() == heap->fixed_cow_array_map()) {
214 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000215#ifdef DEBUG
216 for (int i = 0; i < elements->length(); i++) {
217 ASSERT(!elements->get(i)->IsJSObject());
218 }
219#endif
220 } else {
221 for (int i = 0; i < elements->length(); i++) {
222 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000223 ASSERT(value->IsSmi() ||
224 value->IsTheHole() ||
225 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000226 if (value->IsJSObject()) {
227 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000228 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
229 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000230 if (!maybe_result->ToObject(&result)) return maybe_result;
231 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000232 elements->set(i, result);
233 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000234 }
235 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000236 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000237 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000238 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000239 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000240 int capacity = element_dictionary->Capacity();
241 for (int i = 0; i < capacity; i++) {
242 Object* k = element_dictionary->KeyAt(i);
243 if (element_dictionary->IsKey(k)) {
244 Object* value = element_dictionary->ValueAt(i);
245 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000246 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000247 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
248 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000249 if (!maybe_result->ToObject(&result)) return maybe_result;
250 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000251 element_dictionary->ValueAtPut(i, result);
252 }
253 }
254 }
255 break;
256 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000257 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000258 UNIMPLEMENTED();
259 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000260 case EXTERNAL_PIXEL_ELEMENTS:
261 case EXTERNAL_BYTE_ELEMENTS:
262 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
263 case EXTERNAL_SHORT_ELEMENTS:
264 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
265 case EXTERNAL_INT_ELEMENTS:
266 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
267 case EXTERNAL_FLOAT_ELEMENTS:
268 case EXTERNAL_DOUBLE_ELEMENTS:
269 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000270 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000271 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000272 }
273 return copy;
274}
275
276
ager@chromium.org236ad962008-09-25 09:45:57 +0000277static Handle<Map> ComputeObjectLiteralMap(
278 Handle<Context> context,
279 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000280 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000281 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000282 int properties_length = constant_properties->length();
283 int number_of_properties = properties_length / 2;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000284 // Check that there are only symbols and array indices among keys.
285 int number_of_symbol_keys = 0;
286 for (int p = 0; p != properties_length; p += 2) {
287 Object* key = constant_properties->get(p);
288 uint32_t element_index = 0;
289 if (key->IsSymbol()) {
290 number_of_symbol_keys++;
291 } else if (key->ToArrayIndex(&element_index)) {
292 // An index key does not require space in the property backing store.
293 number_of_properties--;
294 } else {
295 // Bail out as a non-symbol non-index key makes caching impossible.
296 // ASSERT to make sure that the if condition after the loop is false.
297 ASSERT(number_of_symbol_keys != number_of_properties);
298 break;
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000300 }
301 // If we only have symbols and array indices among keys then we can
302 // use the map cache in the global context.
303 const int kMaxKeys = 10;
304 if ((number_of_symbol_keys == number_of_properties) &&
305 (number_of_symbol_keys < kMaxKeys)) {
306 // Create the fixed array with the key.
307 Handle<FixedArray> keys =
308 isolate->factory()->NewFixedArray(number_of_symbol_keys);
309 if (number_of_symbol_keys > 0) {
310 int index = 0;
311 for (int p = 0; p < properties_length; p += 2) {
312 Object* key = constant_properties->get(p);
313 if (key->IsSymbol()) {
314 keys->set(index++, key);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000315 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000316 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000317 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000318 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000319 *is_result_from_cache = true;
320 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000321 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000322 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000323 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000324 Handle<Map>(context->object_function()->initial_map()),
325 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000326}
327
328
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000329static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000331 Handle<FixedArray> literals,
332 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000333
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000334
335static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000336 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000337 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000338 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000339 bool should_have_fast_elements,
340 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000341 // Get the global context from the literals array. This is the
342 // context in which the function was created and we use the object
343 // function from this context to create the object literal. We do
344 // not use the object function from the current global context
345 // because this might be the object function from another context
346 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000347 Handle<Context> context =
348 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
349
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000350 // In case we have function literals, we want the object to be in
351 // slow properties mode for now. We don't go in the map cache because
352 // maps with constant functions can't be shared if the functions are
353 // not the same (which is the common case).
354 bool is_result_from_cache = false;
355 Handle<Map> map = has_function_literal
356 ? Handle<Map>(context->object_function()->initial_map())
357 : ComputeObjectLiteralMap(context,
358 constant_properties,
359 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000362
363 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000364 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000365
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000366 // Add the constant properties to the boilerplate.
367 int length = constant_properties->length();
368 bool should_transform =
369 !is_result_from_cache && boilerplate->HasFastProperties();
370 if (should_transform || has_function_literal) {
371 // Normalize the properties of object to avoid n^2 behavior
372 // when extending the object multiple properties. Indicate the number of
373 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000374 JSObject::NormalizeProperties(
375 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000376 }
377
378 for (int index = 0; index < length; index +=2) {
379 Handle<Object> key(constant_properties->get(index+0), isolate);
380 Handle<Object> value(constant_properties->get(index+1), isolate);
381 if (value->IsFixedArray()) {
382 // The value contains the constant_properties of a
383 // simple object or array literal.
384 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
385 value = CreateLiteralBoilerplate(isolate, literals, array);
386 if (value.is_null()) return value;
387 }
388 Handle<Object> result;
389 uint32_t element_index = 0;
390 if (key->IsSymbol()) {
391 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
392 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000393 result = JSObject::SetOwnElement(
394 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000396 Handle<String> name(String::cast(*key));
397 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000398 result = JSObject::SetLocalPropertyIgnoreAttributes(
399 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000401 } else if (key->ToArrayIndex(&element_index)) {
402 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000403 result = JSObject::SetOwnElement(
404 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 } else {
406 // Non-uint32 number.
407 ASSERT(key->IsNumber());
408 double num = key->Number();
409 char arr[100];
410 Vector<char> buffer(arr, ARRAY_SIZE(arr));
411 const char* str = DoubleToCString(num, buffer);
412 Handle<String> name =
413 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000414 result = JSObject::SetLocalPropertyIgnoreAttributes(
415 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000416 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000417 // If setting the property on the boilerplate throws an
418 // exception, the exception is converted to an empty handle in
419 // the handle based operations. In that case, we need to
420 // convert back to an exception.
421 if (result.is_null()) return result;
422 }
423
424 // Transform to fast properties if necessary. For object literals with
425 // containing function literals we defer this operation until after all
426 // computed properties have been assigned so that we can generate
427 // constant function properties.
428 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000429 JSObject::TransformToFastProperties(
430 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431 }
432
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000433 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000434}
435
436
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000437MaybeObject* TransitionElements(Handle<Object> object,
438 ElementsKind to_kind,
439 Isolate* isolate) {
440 HandleScope scope(isolate);
441 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
442 ElementsKind from_kind =
443 Handle<JSObject>::cast(object)->map()->elements_kind();
444 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
445 Handle<Object> result = JSObject::TransitionElementsKind(
446 Handle<JSObject>::cast(object), to_kind);
447 if (result.is_null()) return isolate->ThrowIllegalOperation();
448 return *result;
449 }
450 return isolate->ThrowIllegalOperation();
451}
452
453
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000454static const int kSmiOnlyLiteralMinimumLength = 1024;
455
456
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000457Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000458 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000459 Handle<FixedArray> literals,
460 Handle<FixedArray> elements) {
461 // Create the JSArray.
462 Handle<JSFunction> constructor(
463 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000464 Handle<JSArray> object =
465 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000466
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000467 ElementsKind constant_elements_kind =
468 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
469 Handle<FixedArrayBase> constant_elements_values(
470 FixedArrayBase::cast(elements->get(1)));
471
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000472 Context* global_context = isolate->context()->global_context();
473 if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
474 object->set_map(Map::cast(global_context->smi_js_array_map()));
475 } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
476 object->set_map(Map::cast(global_context->double_js_array_map()));
477 } else {
478 object->set_map(Map::cast(global_context->object_js_array_map()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000479 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000480
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000481 Handle<FixedArrayBase> copied_elements_values;
482 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
483 ASSERT(FLAG_smi_only_arrays);
484 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
485 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000486 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000487 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
488 constant_elements_kind == FAST_ELEMENTS);
489 const bool is_cow =
490 (constant_elements_values->map() ==
491 isolate->heap()->fixed_cow_array_map());
492 if (is_cow) {
493 copied_elements_values = constant_elements_values;
494#if DEBUG
495 Handle<FixedArray> fixed_array_values =
496 Handle<FixedArray>::cast(copied_elements_values);
497 for (int i = 0; i < fixed_array_values->length(); i++) {
498 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
499 }
500#endif
501 } else {
502 Handle<FixedArray> fixed_array_values =
503 Handle<FixedArray>::cast(constant_elements_values);
504 Handle<FixedArray> fixed_array_values_copy =
505 isolate->factory()->CopyFixedArray(fixed_array_values);
506 copied_elements_values = fixed_array_values_copy;
507 for (int i = 0; i < fixed_array_values->length(); i++) {
508 Object* current = fixed_array_values->get(i);
509 if (current->IsFixedArray()) {
510 // The value contains the constant_properties of a
511 // simple object or array literal.
512 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
513 Handle<Object> result =
514 CreateLiteralBoilerplate(isolate, literals, fa);
515 if (result.is_null()) return result;
516 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000517 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000518 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000519 }
520 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000521 object->set_elements(*copied_elements_values);
522 object->set_length(Smi::FromInt(copied_elements_values->length()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000523
524 // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
525 // on or the object is larger than the threshold.
526 if (!FLAG_smi_only_arrays &&
527 constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
528 if (object->GetElementsKind() != FAST_ELEMENTS) {
529 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
530 }
531 }
532
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000533 return object;
534}
535
536
537static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000539 Handle<FixedArray> literals,
540 Handle<FixedArray> array) {
541 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000542 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000543 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000544 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 return CreateObjectLiteralBoilerplate(isolate,
546 literals,
547 elements,
548 true,
549 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000550 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000551 return CreateObjectLiteralBoilerplate(isolate,
552 literals,
553 elements,
554 false,
555 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000556 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000557 return Runtime::CreateArrayLiteralBoilerplate(
558 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000559 default:
560 UNREACHABLE();
561 return Handle<Object>::null();
562 }
563}
564
565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000566RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000567 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000568 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000569 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000570 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000571 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000572 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000573 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
574 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575
576 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 Handle<Object> boilerplate(literals->get(literals_index), isolate);
578 if (*boilerplate == isolate->heap()->undefined_value()) {
579 boilerplate = CreateObjectLiteralBoilerplate(isolate,
580 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000581 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000582 should_have_fast_elements,
583 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000584 if (boilerplate.is_null()) return Failure::Exception();
585 // Update the functions literal and return the boilerplate.
586 literals->set(literals_index, *boilerplate);
587 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000588 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589}
590
591
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000592RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000593 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000594 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000595 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000596 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000597 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000598 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
600 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000601
602 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000603 Handle<Object> boilerplate(literals->get(literals_index), isolate);
604 if (*boilerplate == isolate->heap()->undefined_value()) {
605 boilerplate = CreateObjectLiteralBoilerplate(isolate,
606 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000607 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000608 should_have_fast_elements,
609 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000610 if (boilerplate.is_null()) return Failure::Exception();
611 // Update the functions literal and return the boilerplate.
612 literals->set(literals_index, *boilerplate);
613 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000615}
616
617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000618RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000619 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000620 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000621 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000622 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000623 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000624
625 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000626 Handle<Object> boilerplate(literals->get(literals_index), isolate);
627 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000628 boilerplate =
629 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000630 if (boilerplate.is_null()) return Failure::Exception();
631 // Update the functions literal and return the boilerplate.
632 literals->set(literals_index, *boilerplate);
633 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000634 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000635}
636
637
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000638RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000639 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000640 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000641 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000642 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000643 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000644
645 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000646 Handle<Object> boilerplate(literals->get(literals_index), isolate);
647 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000648 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000649 boilerplate =
650 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000651 if (boilerplate.is_null()) return Failure::Exception();
652 // Update the functions literal and return the boilerplate.
653 literals->set(literals_index, *boilerplate);
654 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000655 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000656 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000657 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000658 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000659 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000660}
661
662
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000663RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
664 ASSERT(args.length() == 2);
665 Object* handler = args[0];
666 Object* prototype = args[1];
667 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000668 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000669 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
670}
671
672
lrn@chromium.org34e60782011-09-15 07:25:40 +0000673RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
674 ASSERT(args.length() == 4);
675 Object* handler = args[0];
676 Object* call_trap = args[1];
677 Object* construct_trap = args[2];
678 Object* prototype = args[3];
679 Object* used_prototype =
680 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
681 return isolate->heap()->AllocateJSFunctionProxy(
682 handler, call_trap, construct_trap, used_prototype);
683}
684
685
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000686RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
687 ASSERT(args.length() == 1);
688 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000689 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000690}
691
692
lrn@chromium.org34e60782011-09-15 07:25:40 +0000693RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
694 ASSERT(args.length() == 1);
695 Object* obj = args[0];
696 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
697}
698
699
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000700RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
701 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000702 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000703 return proxy->handler();
704}
705
706
lrn@chromium.org34e60782011-09-15 07:25:40 +0000707RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
708 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000709 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000710 return proxy->call_trap();
711}
712
713
714RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
715 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000716 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000717 return proxy->construct_trap();
718}
719
720
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000721RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
722 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000723 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000724 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000725 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000726}
727
728
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000729RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
730 HandleScope scope(isolate);
731 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000732 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000733 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
734 holder->set_table(*table);
735 return *holder;
736}
737
738
739RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
740 HandleScope scope(isolate);
741 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000742 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000743 Handle<Object> key(args[1]);
744 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
745 table = ObjectHashSetAdd(table, key);
746 holder->set_table(*table);
747 return isolate->heap()->undefined_symbol();
748}
749
750
751RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
752 HandleScope scope(isolate);
753 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000754 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000755 Handle<Object> key(args[1]);
756 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
757 return isolate->heap()->ToBoolean(table->Contains(*key));
758}
759
760
761RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
762 HandleScope scope(isolate);
763 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000764 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000765 Handle<Object> key(args[1]);
766 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
767 table = ObjectHashSetRemove(table, key);
768 holder->set_table(*table);
769 return isolate->heap()->undefined_symbol();
770}
771
772
773RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
774 HandleScope scope(isolate);
775 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000776 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000777 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
778 holder->set_table(*table);
779 return *holder;
780}
781
782
783RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
784 HandleScope scope(isolate);
785 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000786 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000787 Handle<Object> key(args[1]);
788 return ObjectHashTable::cast(holder->table())->Lookup(*key);
789}
790
791
792RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
793 HandleScope scope(isolate);
794 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000795 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000796 Handle<Object> key(args[1]);
797 Handle<Object> value(args[2]);
798 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
799 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
800 holder->set_table(*new_table);
801 return *value;
802}
803
804
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000805RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
806 HandleScope scope(isolate);
807 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000808 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000809 ASSERT(weakmap->map()->inobject_properties() == 0);
810 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
811 weakmap->set_table(*table);
812 weakmap->set_next(Smi::FromInt(0));
813 return *weakmap;
814}
815
816
817RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
818 NoHandleAllocation ha;
819 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000820 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
821 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000822 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000823}
824
825
826RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
827 HandleScope scope(isolate);
828 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000829 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
830 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000831 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000832 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000833 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
834 weakmap->set_table(*new_table);
835 return *value;
836}
837
838
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000839RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840 NoHandleAllocation ha;
841 ASSERT(args.length() == 1);
842 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000843 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000844 return JSObject::cast(obj)->class_name();
845}
846
ager@chromium.org7c537e22008-10-16 08:43:32 +0000847
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000848RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
849 NoHandleAllocation ha;
850 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000851 CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000852 Object* obj = input_obj;
853 // We don't expect access checks to be needed on JSProxy objects.
854 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000855 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000856 if (obj->IsAccessCheckNeeded() &&
857 !isolate->MayNamedAccess(JSObject::cast(obj),
858 isolate->heap()->Proto_symbol(),
859 v8::ACCESS_GET)) {
860 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
861 return isolate->heap()->undefined_value();
862 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000863 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000864 } while (obj->IsJSObject() &&
865 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000866 return obj;
867}
868
869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000870RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871 NoHandleAllocation ha;
872 ASSERT(args.length() == 2);
873 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
874 Object* O = args[0];
875 Object* V = args[1];
876 while (true) {
877 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000878 if (prototype->IsNull()) return isolate->heap()->false_value();
879 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880 V = prototype;
881 }
882}
883
884
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000885// Recursively traverses hidden prototypes if property is not found
886static void GetOwnPropertyImplementation(JSObject* obj,
887 String* name,
888 LookupResult* result) {
889 obj->LocalLookupRealNamedProperty(name, result);
890
891 if (!result->IsProperty()) {
892 Object* proto = obj->GetPrototype();
893 if (proto->IsJSObject() &&
894 JSObject::cast(proto)->map()->is_hidden_prototype())
895 GetOwnPropertyImplementation(JSObject::cast(proto),
896 name, result);
897 }
898}
899
900
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000901static bool CheckAccessException(LookupResult* result,
902 v8::AccessType access_type) {
903 if (result->type() == CALLBACKS) {
904 Object* callback = result->GetCallbackObject();
905 if (callback->IsAccessorInfo()) {
906 AccessorInfo* info = AccessorInfo::cast(callback);
907 bool can_access =
908 (access_type == v8::ACCESS_HAS &&
909 (info->all_can_read() || info->all_can_write())) ||
910 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
911 (access_type == v8::ACCESS_SET && info->all_can_write());
912 return can_access;
913 }
914 }
915
916 return false;
917}
918
919
920static bool CheckAccess(JSObject* obj,
921 String* name,
922 LookupResult* result,
923 v8::AccessType access_type) {
924 ASSERT(result->IsProperty());
925
926 JSObject* holder = result->holder();
927 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000929 while (true) {
930 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000932 // Access check callback denied the access, but some properties
933 // can have a special permissions which override callbacks descision
934 // (currently see v8::AccessControl).
935 break;
936 }
937
938 if (current == holder) {
939 return true;
940 }
941
942 current = JSObject::cast(current->GetPrototype());
943 }
944
945 // API callbacks can have per callback access exceptions.
946 switch (result->type()) {
947 case CALLBACKS: {
948 if (CheckAccessException(result, access_type)) {
949 return true;
950 }
951 break;
952 }
953 case INTERCEPTOR: {
954 // If the object has an interceptor, try real named properties.
955 // Overwrite the result to fetch the correct property later.
956 holder->LookupRealNamedProperty(name, result);
957 if (result->IsProperty()) {
958 if (CheckAccessException(result, access_type)) {
959 return true;
960 }
961 }
962 break;
963 }
964 default:
965 break;
966 }
967
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000968 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000969 return false;
970}
971
972
973// TODO(1095): we should traverse hidden prototype hierachy as well.
974static bool CheckElementAccess(JSObject* obj,
975 uint32_t index,
976 v8::AccessType access_type) {
977 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000978 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000979 return false;
980 }
981
982 return true;
983}
984
985
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000986// Enumerator used as indices into the array returned from GetOwnProperty
987enum PropertyDescriptorIndices {
988 IS_ACCESSOR_INDEX,
989 VALUE_INDEX,
990 GETTER_INDEX,
991 SETTER_INDEX,
992 WRITABLE_INDEX,
993 ENUMERABLE_INDEX,
994 CONFIGURABLE_INDEX,
995 DESCRIPTOR_SIZE
996};
997
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000998// Returns an array with the property description:
999// if args[1] is not a property on args[0]
1000// returns undefined
1001// if args[1] is a data property on args[0]
1002// [false, value, Writeable, Enumerable, Configurable]
1003// if args[1] is an accessor on args[0]
1004// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001005RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001006 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001007 Heap* heap = isolate->heap();
1008 HandleScope scope(isolate);
1009 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1010 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001011 LookupResult result(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001012 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1013 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001014
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001015 // This could be an element.
1016 uint32_t index;
1017 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001018 switch (obj->HasLocalElement(index)) {
1019 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001020 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001021
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001022 case JSObject::STRING_CHARACTER_ELEMENT: {
1023 // Special handling of string objects according to ECMAScript 5
1024 // 15.5.5.2. Note that this might be a string object with elements
1025 // other than the actual string value. This is covered by the
1026 // subsequent cases.
1027 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1028 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001029 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001030
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001031 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001032 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001033 elms->set(WRITABLE_INDEX, heap->false_value());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001034 elms->set(ENUMERABLE_INDEX, heap->true_value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001035 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001036 return *desc;
1037 }
1038
1039 case JSObject::INTERCEPTED_ELEMENT:
1040 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001041 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001042 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001043 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001044 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001045 elms->set(WRITABLE_INDEX, heap->true_value());
1046 elms->set(ENUMERABLE_INDEX, heap->true_value());
1047 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001048 return *desc;
1049 }
1050
1051 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001052 Handle<JSObject> holder = obj;
1053 if (obj->IsJSGlobalProxy()) {
1054 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001055 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001056 ASSERT(proto->IsJSGlobalObject());
1057 holder = Handle<JSObject>(JSObject::cast(proto));
1058 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001059 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001060 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001061 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001062 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001063 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001064 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001065 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001066 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001067 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001068 PropertyDetails details = dictionary->DetailsAt(entry);
1069 switch (details.type()) {
1070 case CALLBACKS: {
1071 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001072 AccessorPair* accessors =
1073 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001074 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001075 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001076 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001077 }
1078 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001079 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001080 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001081 break;
1082 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001083 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001084 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001085 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001086 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001087 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001088 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001090 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001091 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001092 default:
1093 UNREACHABLE();
1094 break;
1095 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001096 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1097 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001098 return *desc;
1099 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001100 }
1101 }
1102
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001103 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001104 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001105
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001106 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001107 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001108 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001109
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001110 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001111 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001112 }
1113
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001114 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1115 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001116
1117 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001118 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001119
1120 if (is_js_accessor) {
1121 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001122 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001123
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001124 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001125 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001126 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001127 }
1128 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001129 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001130 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001131 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001132 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1133 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001134
1135 PropertyAttributes attrs;
1136 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001137 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001138 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1139 if (!maybe_value->ToObject(&value)) return maybe_value;
1140 }
1141 elms->set(VALUE_INDEX, value);
1142 }
1143
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001144 return *desc;
1145}
1146
1147
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001148RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001149 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001150 CONVERT_ARG_CHECKED(JSObject, obj, 0);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001151 return obj->PreventExtensions();
1152}
1153
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001155RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001156 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001157 CONVERT_ARG_CHECKED(JSObject, obj, 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001158 if (obj->IsJSGlobalProxy()) {
1159 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001160 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001161 ASSERT(proto->IsJSGlobalObject());
1162 obj = JSObject::cast(proto);
1163 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001164 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001165}
1166
1167
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001168RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001169 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001170 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001171 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
1172 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
1173 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001174 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1175 if (result.is_null()) return Failure::Exception();
1176 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001177}
1178
1179
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001180RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001181 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001182 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001183 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001184 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185}
1186
1187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001188RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001189 ASSERT(args.length() == 1);
1190 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001191 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001192 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193}
1194
1195
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001196RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001198 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
1199 CONVERT_SMI_ARG_CHECKED(index, 1)
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001200 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1201 InstanceType type = templ->map()->instance_type();
1202 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1203 type == OBJECT_TEMPLATE_INFO_TYPE);
1204 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001205 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001206 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1207 } else {
1208 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1209 }
1210 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001211}
1212
1213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001214RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001215 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001216 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001217 Map* old_map = object->map();
1218 bool needs_access_checks = old_map->is_access_check_needed();
1219 if (needs_access_checks) {
1220 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001221 Object* new_map;
1222 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1223 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1224 }
ager@chromium.org32912102009-01-16 10:38:43 +00001225
1226 Map::cast(new_map)->set_is_access_check_needed(false);
1227 object->set_map(Map::cast(new_map));
1228 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001229 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001230}
1231
1232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001233RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001234 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001235 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001236 Map* old_map = object->map();
1237 if (!old_map->is_access_check_needed()) {
1238 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001239 Object* new_map;
1240 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1241 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1242 }
ager@chromium.org32912102009-01-16 10:38:43 +00001243
1244 Map::cast(new_map)->set_is_access_check_needed(true);
1245 object->set_map(Map::cast(new_map));
1246 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001247 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001248}
1249
1250
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001251static Failure* ThrowRedeclarationError(Isolate* isolate,
1252 const char* type,
1253 Handle<String> name) {
1254 HandleScope scope(isolate);
1255 Handle<Object> type_handle =
1256 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257 Handle<Object> args[2] = { type_handle, name };
1258 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001259 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1260 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261}
1262
1263
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001264RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001265 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001266 HandleScope scope(isolate);
1267 Handle<GlobalObject> global = Handle<GlobalObject>(
1268 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269
ager@chromium.org3811b432009-10-28 14:53:37 +00001270 Handle<Context> context = args.at<Context>(0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001271 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001272 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001273
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274 // Traverse the name/value pairs and set the properties.
1275 int length = pairs->length();
1276 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001277 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001279 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280
1281 // We have to declare a global const property. To capture we only
1282 // assign to it when evaluating the assignment for "const x =
1283 // <expr>" the initial value is the hole.
1284 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001285 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 if (value->IsUndefined() || is_const_property) {
1287 // Lookup the property in the global object, and don't set the
1288 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001289 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290 global->Lookup(*name, &lookup);
1291 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001292 // We found an existing property. Unless it was an interceptor
1293 // that claims the property is absent, skip this declaration.
1294 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295 continue;
1296 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001297 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1298 if (attributes != ABSENT) {
1299 continue;
1300 }
1301 // Fall-through and introduce the absent property by using
1302 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303 }
1304 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001305 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001306 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001307 Handle<SharedFunctionInfo> shared =
1308 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001310 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1311 context,
1312 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001313 value = function;
1314 }
1315
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001316 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317 global->LocalLookup(*name, &lookup);
1318
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001319 // Compute the property attributes. According to ECMA-262, section
1320 // 13, page 71, the property must be read-only and
1321 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1322 // property as read-only, so we don't either.
1323 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001324 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001325 attr |= DONT_DELETE;
1326 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001327 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001328 if (is_const_property || (is_native && is_function_declaration)) {
1329 attr |= READ_ONLY;
1330 }
1331
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001332 // Safari does not allow the invocation of callback setters for
1333 // function declarations. To mimic this behavior, we do not allow
1334 // the invocation of setters for function values. This makes a
1335 // difference for global functions with the same names as event
1336 // handlers such as "function onload() {}". Firefox does call the
1337 // onload setter in those case and Safari does not. We follow
1338 // Safari for compatibility.
1339 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001340 // Do not change DONT_DELETE to false from true.
1341 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001342 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001343 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001344 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1345
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001346 RETURN_IF_EMPTY_HANDLE(
1347 isolate,
1348 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1349 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001350 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001351 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1352 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1353 ? kNonStrictMode : kStrictMode;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001354 RETURN_IF_EMPTY_HANDLE(
1355 isolate,
1356 JSReceiver::SetProperty(global, name, value,
1357 static_cast<PropertyAttributes>(attr),
1358 strict_mode_flag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001359 }
1360 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001361
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001362 ASSERT(!isolate->has_pending_exception());
1363 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001364}
1365
1366
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001367RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001368 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001369 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001371 // Declarations are always made in a function or global context. In the
1372 // case of eval code, the context passed is the context of the caller,
1373 // which may be some nested context and not the declaration context.
1374 RUNTIME_ASSERT(args[0]->IsContext());
1375 Handle<Context> context(Context::cast(args[0])->declaration_context());
1376
ager@chromium.org7c537e22008-10-16 08:43:32 +00001377 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001378 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001379 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001380 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001381
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001382 int index;
1383 PropertyAttributes attributes;
1384 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001385 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001386 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001387 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001388
1389 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001390 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001391 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1392 // Functions are not read-only.
1393 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1394 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001395 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001396 }
1397
1398 // Initialize it if necessary.
1399 if (*initial_value != NULL) {
1400 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001401 ASSERT(holder.is_identical_to(context));
1402 if (((attributes & READ_ONLY) == 0) ||
1403 context->get(index)->IsTheHole()) {
1404 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001405 }
1406 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001407 // Slow case: The property is in the context extension object of a
1408 // function context or the global object of a global context.
1409 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001410 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001411 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001412 JSReceiver::SetProperty(object, name, initial_value, mode,
1413 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001414 }
1415 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001416
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001418 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001419 // "declared" in the function context's extension context or as a
1420 // property of the the global object.
1421 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001422 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001423 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001424 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001425 // Context extension objects are allocated lazily.
1426 ASSERT(context->IsFunctionContext());
1427 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001428 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001429 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001430 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001431 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001432
ager@chromium.org7c537e22008-10-16 08:43:32 +00001433 // Declare the property by setting it to the initial value if provided,
1434 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1435 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001436 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001437 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001438 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001439 // Declaring a const context slot is a conflicting declaration if
1440 // there is a callback with that name in a prototype. It is
1441 // allowed to introduce const variables in
1442 // JSContextExtensionObjects. They are treated specially in
1443 // SetProperty and no setters are invoked for those since they are
1444 // not real JSObjects.
1445 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001446 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001447 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001448 object->Lookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001449 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001450 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001451 }
1452 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001453 RETURN_IF_EMPTY_HANDLE(
1454 isolate,
1455 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001456 }
1457
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001458 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001459}
1460
1461
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001462RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001463 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001464 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001465 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001466 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467
1468 // Determine if we need to assign to the variable if it already
1469 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001470 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1471 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001473 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001474 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001475 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001476 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1477 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1478 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001479
1480 // According to ECMA-262, section 12.2, page 62, the property must
1481 // not be deletable.
1482 PropertyAttributes attributes = DONT_DELETE;
1483
1484 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001485 // there, there is a property with this name in the prototype chain.
1486 // We follow Safari and Firefox behavior and only set the property
1487 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001488 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001489 // Note that objects can have hidden prototypes, so we need to traverse
1490 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001491 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001492 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001493 while (object->IsJSObject() &&
1494 JSObject::cast(object)->map()->is_hidden_prototype()) {
1495 JSObject* raw_holder = JSObject::cast(object);
1496 raw_holder->LocalLookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001497 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001498 HandleScope handle_scope(isolate);
1499 Handle<JSObject> holder(raw_holder);
1500 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1501 // Update the raw pointer in case it's changed due to GC.
1502 raw_holder = *holder;
1503 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1504 // Found an interceptor that's not read only.
1505 if (assign) {
1506 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001507 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001508 } else {
1509 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001510 }
1511 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001512 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001513 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514 }
1515
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001516 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001517 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001518 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001519 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001520 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001521 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001522}
1523
1524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001525RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001526 // All constants are declared with an initial value. The name
1527 // of the constant is the first argument and the initial value
1528 // is the second.
1529 RUNTIME_ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001530 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531 Handle<Object> value = args.at<Object>(1);
1532
1533 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001534 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535
1536 // According to ECMA-262, section 12.2, page 62, the property must
1537 // not be deletable. Since it's a const, it must be READ_ONLY too.
1538 PropertyAttributes attributes =
1539 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1540
1541 // Lookup the property locally in the global object. If it isn't
1542 // there, we add the property and take special precautions to always
1543 // add it as a local property even in case of callbacks in the
1544 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001545 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001546 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001547 global->LocalLookup(*name, &lookup);
1548 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001549 return global->SetLocalPropertyIgnoreAttributes(*name,
1550 *value,
1551 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001552 }
1553
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001554 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001556 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001557 HandleScope handle_scope(isolate);
1558 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001559
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001560 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561 // property through an interceptor and only do it if it's
1562 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001563 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001564 RETURN_IF_EMPTY_HANDLE(
1565 isolate,
1566 JSReceiver::SetProperty(global, name, value, attributes,
1567 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 return *value;
1569 }
1570
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001571 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572 // constant. For now, we determine this by checking if the
1573 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001574 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001575 PropertyType type = lookup.type();
1576 if (type == FIELD) {
1577 FixedArray* properties = global->properties();
1578 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001579 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001580 properties->set(index, *value);
1581 }
1582 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001583 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1584 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001585 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001586 }
1587 } else {
1588 // Ignore re-initialization of constants that have already been
1589 // assigned a function value.
1590 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1591 }
1592
1593 // Use the set value as the result of the operation.
1594 return *value;
1595}
1596
1597
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001598RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001599 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001600 ASSERT(args.length() == 3);
1601
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001602 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001603 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001604
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001605 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001606 RUNTIME_ASSERT(args[1]->IsContext());
1607 Handle<Context> context(Context::cast(args[1])->declaration_context());
1608
1609 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001610
1611 int index;
1612 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001613 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001614 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001615 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001616 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001619 ASSERT(holder->IsContext());
1620 // Property was found in a context. Perform the assignment if we
1621 // found some non-constant or an uninitialized constant.
1622 Handle<Context> context = Handle<Context>::cast(holder);
1623 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1624 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001625 }
1626 return *value;
1627 }
1628
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001629 // The property could not be found, we introduce it as a property of the
1630 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001631 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001632 Handle<JSObject> global = Handle<JSObject>(
1633 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001634 // Strict mode not needed (const disallowed in strict mode).
1635 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001636 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001637 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001638 return *value;
1639 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001640
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001641 // The property was present in some function's context extension object,
1642 // as a property on the subject of a with, or as a property of the global
1643 // object.
1644 //
1645 // In most situations, eval-introduced consts should still be present in
1646 // the context extension object. However, because declaration and
1647 // initialization are separate, the property might have been deleted
1648 // before we reach the initialization point.
1649 //
1650 // Example:
1651 //
1652 // function f() { eval("delete x; const x;"); }
1653 //
1654 // In that case, the initialization behaves like a normal assignment.
1655 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001656
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001657 if (*object == context->extension()) {
1658 // This is the property that was introduced by the const declaration.
1659 // Set it if it hasn't been set before. NOTE: We cannot use
1660 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001661 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001662 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001663 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001664 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1665
1666 PropertyType type = lookup.type();
1667 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001668 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001669 int index = lookup.GetFieldIndex();
1670 if (properties->get(index)->IsTheHole()) {
1671 properties->set(index, *value);
1672 }
1673 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001674 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1675 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001676 }
1677 } else {
1678 // We should not reach here. Any real, named property should be
1679 // either a field or a dictionary slot.
1680 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001681 }
1682 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001683 // The property was found on some other object. Set it if it is not a
1684 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001685 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001686 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001687 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001688 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001689 JSReceiver::SetProperty(object, name, value, attributes,
1690 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001691 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001692 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001693
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001694 return *value;
1695}
1696
1697
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001698RUNTIME_FUNCTION(MaybeObject*,
1699 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001700 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001701 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001702 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001703 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001704 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001705 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001706 }
1707 return *object;
1708}
1709
1710
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001711RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001712 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001713 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001714 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1715 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001716 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001717 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001718 CONVERT_SMI_ARG_CHECKED(index, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001719 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001720 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001721 RUNTIME_ASSERT(index >= 0);
1722 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001723 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001724 Handle<Object> result = RegExpImpl::Exec(regexp,
1725 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001726 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001727 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001728 if (result.is_null()) return Failure::Exception();
1729 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001730}
1731
1732
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001733RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001734 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001735 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001736 if (elements_count < 0 ||
1737 elements_count > FixedArray::kMaxLength ||
1738 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001739 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001740 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001741 Object* new_object;
1742 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001743 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001744 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1745 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001746 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1748 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001749 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1750 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001751 {
1752 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001753 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001754 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001756 }
1757 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001758 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001759 array->set_elements(elements);
1760 array->set_length(Smi::FromInt(elements_count));
1761 // Write in-object properties after the length of the array.
1762 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1763 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1764 return array;
1765}
1766
1767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001768RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001769 AssertNoAllocation no_alloc;
1770 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001771 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1772 CONVERT_ARG_CHECKED(String, source, 1);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001773
1774 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001775 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001776
1777 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001778 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001779
1780 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001781 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001782
1783 Map* map = regexp->map();
1784 Object* constructor = map->constructor();
1785 if (constructor->IsJSFunction() &&
1786 JSFunction::cast(constructor)->initial_map() == map) {
1787 // If we still have the original map, set in-object properties directly.
1788 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001789 // Both true and false are immovable immortal objects so no need for write
1790 // barrier.
1791 regexp->InObjectPropertyAtPut(
1792 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1793 regexp->InObjectPropertyAtPut(
1794 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1795 regexp->InObjectPropertyAtPut(
1796 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001797 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1798 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001799 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001800 return regexp;
1801 }
1802
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001803 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001804 PropertyAttributes final =
1805 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1806 PropertyAttributes writable =
1807 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001808 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001809 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001810 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001811 source,
1812 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001813 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001814 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001815 global,
1816 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001817 ASSERT(!result->IsFailure());
1818 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001819 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001820 ignoreCase,
1821 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001822 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001823 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001824 multiline,
1825 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001826 ASSERT(!result->IsFailure());
1827 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001828 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001829 Smi::FromInt(0),
1830 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001831 ASSERT(!result->IsFailure());
1832 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001833 return regexp;
1834}
1835
1836
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001837RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001838 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001839 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001840 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001841 // This is necessary to enable fast checks for absence of elements
1842 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001843 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001844 return Smi::FromInt(0);
1845}
1846
1847
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001848static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1849 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001850 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001851 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001852 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1853 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1854 Handle<JSFunction> optimized =
1855 isolate->factory()->NewFunction(key,
1856 JS_OBJECT_TYPE,
1857 JSObject::kHeaderSize,
1858 code,
1859 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001860 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001861 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001862 return optimized;
1863}
1864
1865
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001866RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001867 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001868 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001869 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001870
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001871 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1872 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1873 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1874 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1875 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1876 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1877 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001878
1879 return *holder;
1880}
1881
1882
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001883RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001884 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001885 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001886
1887 if (!callable->IsJSFunction()) {
1888 HandleScope scope(isolate);
1889 bool threw = false;
1890 Handle<Object> delegate =
1891 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1892 if (threw) return Failure::Exception();
1893 callable = JSFunction::cast(*delegate);
1894 }
1895 JSFunction* function = JSFunction::cast(callable);
1896
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001897 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001898 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001899 return isolate->heap()->undefined_value();
1900 }
1901 // Returns undefined for strict or native functions, or
1902 // the associated global receiver for "normal" functions.
1903
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001904 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001905 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001906 return global_context->global()->global_receiver();
1907}
1908
1909
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001910RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001911 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001912 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001913 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001914 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001915 Handle<String> pattern = args.at<String>(2);
1916 Handle<String> flags = args.at<String>(3);
1917
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001918 // Get the RegExp function from the context in the literals array.
1919 // This is the RegExp function from the context in which the
1920 // function was created. We do not use the RegExp function from the
1921 // current global context because this might be the RegExp function
1922 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001923 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001924 Handle<JSFunction>(
1925 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 // Compute the regular expression literal.
1927 bool has_pending_exception;
1928 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001929 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1930 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001931 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001932 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001933 return Failure::Exception();
1934 }
1935 literals->set(index, *regexp);
1936 return *regexp;
1937}
1938
1939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001940RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001941 NoHandleAllocation ha;
1942 ASSERT(args.length() == 1);
1943
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001944 CONVERT_ARG_CHECKED(JSFunction, f, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001945 return f->shared()->name();
1946}
1947
1948
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001949RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001950 NoHandleAllocation ha;
1951 ASSERT(args.length() == 2);
1952
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001953 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1954 CONVERT_ARG_CHECKED(String, name, 1);
ager@chromium.org236ad962008-09-25 09:45:57 +00001955 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001956 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001957}
1958
1959
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001960RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1961 NoHandleAllocation ha;
1962 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001963 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001964 return isolate->heap()->ToBoolean(
1965 f->shared()->name_should_print_as_anonymous());
1966}
1967
1968
1969RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1970 NoHandleAllocation ha;
1971 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001972 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001973 f->shared()->set_name_should_print_as_anonymous(true);
1974 return isolate->heap()->undefined_value();
1975}
1976
1977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001978RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001979 NoHandleAllocation ha;
1980 ASSERT(args.length() == 1);
1981
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001982 CONVERT_ARG_CHECKED(JSFunction, f, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001983 Object* obj = f->RemovePrototype();
1984 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001985
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001986 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001987}
1988
1989
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001990RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001991 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001992 ASSERT(args.length() == 1);
1993
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001994 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001995 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1996 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001997
1998 return *GetScriptWrapper(Handle<Script>::cast(script));
1999}
2000
2001
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002002RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002003 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002004 ASSERT(args.length() == 1);
2005
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002006 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002007 Handle<SharedFunctionInfo> shared(f->shared());
2008 return *shared->GetSourceCode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002009}
2010
2011
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002012RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 NoHandleAllocation ha;
2014 ASSERT(args.length() == 1);
2015
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002016 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002017 int pos = fun->shared()->start_position();
2018 return Smi::FromInt(pos);
2019}
2020
2021
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002022RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002023 ASSERT(args.length() == 2);
2024
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002025 CONVERT_ARG_CHECKED(Code, code, 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002026 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2027
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002028 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2029
2030 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002031 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002032}
2033
2034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002035RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002036 NoHandleAllocation ha;
2037 ASSERT(args.length() == 2);
2038
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002039 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2040 CONVERT_ARG_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002041 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002042 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002043}
2044
2045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002046RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002047 NoHandleAllocation ha;
2048 ASSERT(args.length() == 2);
2049
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002050 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2051 CONVERT_SMI_ARG_CHECKED(length, 1);
2052 fun->shared()->set_length(length);
2053 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002054}
2055
2056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002057RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002058 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002059 ASSERT(args.length() == 2);
2060
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002061 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002062 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002063 Object* obj;
2064 { MaybeObject* maybe_obj =
2065 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2066 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2067 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002068 return args[0]; // return TOS
2069}
2070
2071
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002072RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2073 NoHandleAllocation ha;
2074 RUNTIME_ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002075 CONVERT_ARG_CHECKED(JSFunction, function, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002076
2077 MaybeObject* maybe_name =
2078 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2079 String* name;
2080 if (!maybe_name->To(&name)) return maybe_name;
2081
2082 if (function->HasFastProperties()) {
2083 // Construct a new field descriptor with updated attributes.
2084 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2085 int index = instance_desc->Search(name);
2086 ASSERT(index != DescriptorArray::kNotFound);
2087 PropertyDetails details(instance_desc->GetDetails(index));
2088 CallbacksDescriptor new_desc(name,
2089 instance_desc->GetValue(index),
2090 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2091 details.index());
2092 // Construct a new field descriptors array containing the new descriptor.
2093 Object* descriptors_unchecked;
2094 { MaybeObject* maybe_descriptors_unchecked =
2095 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2096 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2097 return maybe_descriptors_unchecked;
2098 }
2099 }
2100 DescriptorArray* new_descriptors =
2101 DescriptorArray::cast(descriptors_unchecked);
2102 // Create a new map featuring the new field descriptors array.
2103 Object* map_unchecked;
2104 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2105 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2106 return maybe_map_unchecked;
2107 }
2108 }
2109 Map* new_map = Map::cast(map_unchecked);
2110 new_map->set_instance_descriptors(new_descriptors);
2111 function->set_map(new_map);
2112 } else { // Dictionary properties.
2113 // Directly manipulate the property details.
2114 int entry = function->property_dictionary()->FindEntry(name);
2115 ASSERT(entry != StringDictionary::kNotFound);
2116 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2117 PropertyDetails new_details(
2118 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2119 details.type(),
2120 details.index());
2121 function->property_dictionary()->DetailsAtPut(entry, new_details);
2122 }
2123 return function;
2124}
2125
2126
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002127RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002128 NoHandleAllocation ha;
2129 ASSERT(args.length() == 1);
2130
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002131 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002132 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002133}
2134
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002135
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002136RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002137 NoHandleAllocation ha;
2138 ASSERT(args.length() == 1);
2139
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002140 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002141 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002142}
2143
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002144
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002145RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002146 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002147 ASSERT(args.length() == 2);
2148
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002149 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002150 Handle<Object> code = args.at<Object>(1);
2151
2152 Handle<Context> context(target->context());
2153
2154 if (!code->IsNull()) {
2155 RUNTIME_ASSERT(code->IsJSFunction());
2156 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002157 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002158
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002159 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002160 return Failure::Exception();
2161 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002162 // Since we don't store the source for this we should never
2163 // optimize this.
2164 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002165 // Set the code, scope info, formal parameter count,
2166 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002167 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002168 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002169 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002170 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002171 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002172 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002173 // Set the source code of the target function to undefined.
2174 // SetCode is only used for built-in constructors like String,
2175 // Array, and Object, and some web code
2176 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002177 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002178 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002179 // Clear the optimization hints related to the compiled code as these are no
2180 // longer valid when the code is overwritten.
2181 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002182 context = Handle<Context>(fun->context());
2183
2184 // Make sure we get a fresh copy of the literal vector to avoid
2185 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002186 int number_of_literals = fun->NumberOfLiterals();
2187 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002188 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002189 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002190 // Insert the object, regexp and array functions in the literals
2191 // array prefix. These are the functions that will be used when
2192 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002193 literals->set(JSFunction::kLiteralGlobalContextIndex,
2194 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002195 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002196 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002197 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002198
2199 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2200 isolate->logger()->LogExistingFunction(
2201 shared, Handle<Code>(shared->code()));
2202 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002203 }
2204
2205 target->set_context(*context);
2206 return *target;
2207}
2208
2209
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002210RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002211 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002212 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002213 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002214 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002215 RUNTIME_ASSERT(num >= 0);
2216 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002217 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002218}
2219
2220
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002221MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2222 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002223 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002224 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002225 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002226 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002227 }
2228 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002229 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002230}
2231
2232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002233RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002234 NoHandleAllocation ha;
2235 ASSERT(args.length() == 2);
2236
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002237 CONVERT_ARG_CHECKED(String, subject, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002238 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002239 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002240
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002241 uint32_t i = 0;
2242 if (index->IsSmi()) {
2243 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002244 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002245 i = value;
2246 } else {
2247 ASSERT(index->IsHeapNumber());
2248 double value = HeapNumber::cast(index)->value();
2249 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002250 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002251
2252 // Flatten the string. If someone wants to get a char at an index
2253 // in a cons string, it is likely that more indices will be
2254 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002255 Object* flat;
2256 { MaybeObject* maybe_flat = subject->TryFlatten();
2257 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2258 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002259 subject = String::cast(flat);
2260
2261 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002262 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002263 }
2264
2265 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002266}
2267
2268
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002269RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002270 NoHandleAllocation ha;
2271 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002272 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002273}
2274
lrn@chromium.org25156de2010-04-06 13:10:27 +00002275
2276class FixedArrayBuilder {
2277 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002278 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2279 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002280 length_(0),
2281 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002282 // Require a non-zero initial size. Ensures that doubling the size to
2283 // extend the array will work.
2284 ASSERT(initial_capacity > 0);
2285 }
2286
2287 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2288 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002289 length_(0),
2290 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002291 // Require a non-zero initial size. Ensures that doubling the size to
2292 // extend the array will work.
2293 ASSERT(backing_store->length() > 0);
2294 }
2295
2296 bool HasCapacity(int elements) {
2297 int length = array_->length();
2298 int required_length = length_ + elements;
2299 return (length >= required_length);
2300 }
2301
2302 void EnsureCapacity(int elements) {
2303 int length = array_->length();
2304 int required_length = length_ + elements;
2305 if (length < required_length) {
2306 int new_length = length;
2307 do {
2308 new_length *= 2;
2309 } while (new_length < required_length);
2310 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002311 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002312 array_->CopyTo(0, *extended_array, 0, length_);
2313 array_ = extended_array;
2314 }
2315 }
2316
2317 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002318 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002319 ASSERT(length_ < capacity());
2320 array_->set(length_, value);
2321 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002322 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002323 }
2324
2325 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002326 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002327 ASSERT(length_ < capacity());
2328 array_->set(length_, value);
2329 length_++;
2330 }
2331
2332 Handle<FixedArray> array() {
2333 return array_;
2334 }
2335
2336 int length() {
2337 return length_;
2338 }
2339
2340 int capacity() {
2341 return array_->length();
2342 }
2343
2344 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002345 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002346 result_array->set_length(Smi::FromInt(length_));
2347 return result_array;
2348 }
2349
2350 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002351 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002352 target_array->set_length(Smi::FromInt(length_));
2353 return target_array;
2354 }
2355
2356 private:
2357 Handle<FixedArray> array_;
2358 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002359 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002360};
2361
2362
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002363// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002364const int kStringBuilderConcatHelperLengthBits = 11;
2365const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002366
2367template <typename schar>
2368static inline void StringBuilderConcatHelper(String*,
2369 schar*,
2370 FixedArray*,
2371 int);
2372
lrn@chromium.org25156de2010-04-06 13:10:27 +00002373typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2374 StringBuilderSubstringLength;
2375typedef BitField<int,
2376 kStringBuilderConcatHelperLengthBits,
2377 kStringBuilderConcatHelperPositionBits>
2378 StringBuilderSubstringPosition;
2379
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002380
2381class ReplacementStringBuilder {
2382 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002383 ReplacementStringBuilder(Heap* heap,
2384 Handle<String> subject,
2385 int estimated_part_count)
2386 : heap_(heap),
2387 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002388 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002389 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002390 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002391 // Require a non-zero initial size. Ensures that doubling the size to
2392 // extend the array will work.
2393 ASSERT(estimated_part_count > 0);
2394 }
2395
lrn@chromium.org25156de2010-04-06 13:10:27 +00002396 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2397 int from,
2398 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002399 ASSERT(from >= 0);
2400 int length = to - from;
2401 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002402 if (StringBuilderSubstringLength::is_valid(length) &&
2403 StringBuilderSubstringPosition::is_valid(from)) {
2404 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2405 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002406 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002407 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002408 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002409 builder->Add(Smi::FromInt(-length));
2410 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002411 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002412 }
2413
2414
2415 void EnsureCapacity(int elements) {
2416 array_builder_.EnsureCapacity(elements);
2417 }
2418
2419
2420 void AddSubjectSlice(int from, int to) {
2421 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002422 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002423 }
2424
2425
2426 void AddString(Handle<String> string) {
2427 int length = string->length();
2428 ASSERT(length > 0);
2429 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002430 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002431 is_ascii_ = false;
2432 }
2433 IncrementCharacterCount(length);
2434 }
2435
2436
2437 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002438 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002439 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002440 }
2441
2442 Handle<String> joined_string;
2443 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002444 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002445 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002446 char* char_buffer = seq->GetChars();
2447 StringBuilderConcatHelper(*subject_,
2448 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002449 *array_builder_.array(),
2450 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002451 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002452 } else {
2453 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002454 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002455 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002456 uc16* char_buffer = seq->GetChars();
2457 StringBuilderConcatHelper(*subject_,
2458 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002459 *array_builder_.array(),
2460 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002461 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002462 }
2463 return joined_string;
2464 }
2465
2466
2467 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002468 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002469 V8::FatalProcessOutOfMemory("String.replace result too large.");
2470 }
2471 character_count_ += by;
2472 }
2473
lrn@chromium.org25156de2010-04-06 13:10:27 +00002474 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002475 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002476 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002477
lrn@chromium.org25156de2010-04-06 13:10:27 +00002478 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002479 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2480 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002481 }
2482
2483
ager@chromium.org04921a82011-06-27 13:21:41 +00002484 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2485 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002486 }
2487
2488
2489 void AddElement(Object* element) {
2490 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002491 ASSERT(array_builder_.capacity() > array_builder_.length());
2492 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002493 }
2494
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002495 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002496 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002497 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002498 int character_count_;
2499 bool is_ascii_;
2500};
2501
2502
2503class CompiledReplacement {
2504 public:
2505 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002506 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002507
2508 void Compile(Handle<String> replacement,
2509 int capture_count,
2510 int subject_length);
2511
2512 void Apply(ReplacementStringBuilder* builder,
2513 int match_from,
2514 int match_to,
2515 Handle<JSArray> last_match_info);
2516
2517 // Number of distinct parts of the replacement pattern.
2518 int parts() {
2519 return parts_.length();
2520 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002521
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002522 bool simple_hint() {
2523 return simple_hint_;
2524 }
2525
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002526 private:
2527 enum PartType {
2528 SUBJECT_PREFIX = 1,
2529 SUBJECT_SUFFIX,
2530 SUBJECT_CAPTURE,
2531 REPLACEMENT_SUBSTRING,
2532 REPLACEMENT_STRING,
2533
2534 NUMBER_OF_PART_TYPES
2535 };
2536
2537 struct ReplacementPart {
2538 static inline ReplacementPart SubjectMatch() {
2539 return ReplacementPart(SUBJECT_CAPTURE, 0);
2540 }
2541 static inline ReplacementPart SubjectCapture(int capture_index) {
2542 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2543 }
2544 static inline ReplacementPart SubjectPrefix() {
2545 return ReplacementPart(SUBJECT_PREFIX, 0);
2546 }
2547 static inline ReplacementPart SubjectSuffix(int subject_length) {
2548 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2549 }
2550 static inline ReplacementPart ReplacementString() {
2551 return ReplacementPart(REPLACEMENT_STRING, 0);
2552 }
2553 static inline ReplacementPart ReplacementSubString(int from, int to) {
2554 ASSERT(from >= 0);
2555 ASSERT(to > from);
2556 return ReplacementPart(-from, to);
2557 }
2558
2559 // If tag <= 0 then it is the negation of a start index of a substring of
2560 // the replacement pattern, otherwise it's a value from PartType.
2561 ReplacementPart(int tag, int data)
2562 : tag(tag), data(data) {
2563 // Must be non-positive or a PartType value.
2564 ASSERT(tag < NUMBER_OF_PART_TYPES);
2565 }
2566 // Either a value of PartType or a non-positive number that is
2567 // the negation of an index into the replacement string.
2568 int tag;
2569 // The data value's interpretation depends on the value of tag:
2570 // tag == SUBJECT_PREFIX ||
2571 // tag == SUBJECT_SUFFIX: data is unused.
2572 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2573 // tag == REPLACEMENT_SUBSTRING ||
2574 // tag == REPLACEMENT_STRING: data is index into array of substrings
2575 // of the replacement string.
2576 // tag <= 0: Temporary representation of the substring of the replacement
2577 // string ranging over -tag .. data.
2578 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2579 // substring objects.
2580 int data;
2581 };
2582
2583 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002584 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002585 Vector<Char> characters,
2586 int capture_count,
2587 int subject_length) {
2588 int length = characters.length();
2589 int last = 0;
2590 for (int i = 0; i < length; i++) {
2591 Char c = characters[i];
2592 if (c == '$') {
2593 int next_index = i + 1;
2594 if (next_index == length) { // No next character!
2595 break;
2596 }
2597 Char c2 = characters[next_index];
2598 switch (c2) {
2599 case '$':
2600 if (i > last) {
2601 // There is a substring before. Include the first "$".
2602 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2603 last = next_index + 1; // Continue after the second "$".
2604 } else {
2605 // Let the next substring start with the second "$".
2606 last = next_index;
2607 }
2608 i = next_index;
2609 break;
2610 case '`':
2611 if (i > last) {
2612 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2613 }
2614 parts->Add(ReplacementPart::SubjectPrefix());
2615 i = next_index;
2616 last = i + 1;
2617 break;
2618 case '\'':
2619 if (i > last) {
2620 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2621 }
2622 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2623 i = next_index;
2624 last = i + 1;
2625 break;
2626 case '&':
2627 if (i > last) {
2628 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2629 }
2630 parts->Add(ReplacementPart::SubjectMatch());
2631 i = next_index;
2632 last = i + 1;
2633 break;
2634 case '0':
2635 case '1':
2636 case '2':
2637 case '3':
2638 case '4':
2639 case '5':
2640 case '6':
2641 case '7':
2642 case '8':
2643 case '9': {
2644 int capture_ref = c2 - '0';
2645 if (capture_ref > capture_count) {
2646 i = next_index;
2647 continue;
2648 }
2649 int second_digit_index = next_index + 1;
2650 if (second_digit_index < length) {
2651 // Peek ahead to see if we have two digits.
2652 Char c3 = characters[second_digit_index];
2653 if ('0' <= c3 && c3 <= '9') { // Double digits.
2654 int double_digit_ref = capture_ref * 10 + c3 - '0';
2655 if (double_digit_ref <= capture_count) {
2656 next_index = second_digit_index;
2657 capture_ref = double_digit_ref;
2658 }
2659 }
2660 }
2661 if (capture_ref > 0) {
2662 if (i > last) {
2663 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2664 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002665 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002666 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2667 last = next_index + 1;
2668 }
2669 i = next_index;
2670 break;
2671 }
2672 default:
2673 i = next_index;
2674 break;
2675 }
2676 }
2677 }
2678 if (length > last) {
2679 if (last == 0) {
2680 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002681 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002682 } else {
2683 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2684 }
2685 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002686 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002687 }
2688
2689 ZoneList<ReplacementPart> parts_;
2690 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002691 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002692};
2693
2694
2695void CompiledReplacement::Compile(Handle<String> replacement,
2696 int capture_count,
2697 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002698 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002699 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002700 String::FlatContent content = replacement->GetFlatContent();
2701 ASSERT(content.IsFlat());
2702 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002703 simple_hint_ = ParseReplacementPattern(&parts_,
2704 content.ToAsciiVector(),
2705 capture_count,
2706 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002707 } else {
2708 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002709 simple_hint_ = ParseReplacementPattern(&parts_,
2710 content.ToUC16Vector(),
2711 capture_count,
2712 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002713 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002714 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002715 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002716 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002717 int substring_index = 0;
2718 for (int i = 0, n = parts_.length(); i < n; i++) {
2719 int tag = parts_[i].tag;
2720 if (tag <= 0) { // A replacement string slice.
2721 int from = -tag;
2722 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002723 replacement_substrings_.Add(
2724 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002725 parts_[i].tag = REPLACEMENT_SUBSTRING;
2726 parts_[i].data = substring_index;
2727 substring_index++;
2728 } else if (tag == REPLACEMENT_STRING) {
2729 replacement_substrings_.Add(replacement);
2730 parts_[i].data = substring_index;
2731 substring_index++;
2732 }
2733 }
2734}
2735
2736
2737void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2738 int match_from,
2739 int match_to,
2740 Handle<JSArray> last_match_info) {
2741 for (int i = 0, n = parts_.length(); i < n; i++) {
2742 ReplacementPart part = parts_[i];
2743 switch (part.tag) {
2744 case SUBJECT_PREFIX:
2745 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2746 break;
2747 case SUBJECT_SUFFIX: {
2748 int subject_length = part.data;
2749 if (match_to < subject_length) {
2750 builder->AddSubjectSlice(match_to, subject_length);
2751 }
2752 break;
2753 }
2754 case SUBJECT_CAPTURE: {
2755 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002756 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002757 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2758 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2759 if (from >= 0 && to > from) {
2760 builder->AddSubjectSlice(from, to);
2761 }
2762 break;
2763 }
2764 case REPLACEMENT_SUBSTRING:
2765 case REPLACEMENT_STRING:
2766 builder->AddString(replacement_substrings_[part.data]);
2767 break;
2768 default:
2769 UNREACHABLE();
2770 }
2771 }
2772}
2773
2774
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002775void FindAsciiStringIndices(Vector<const char> subject,
2776 char pattern,
2777 ZoneList<int>* indices,
2778 unsigned int limit) {
2779 ASSERT(limit > 0);
2780 // Collect indices of pattern in subject using memchr.
2781 // Stop after finding at most limit values.
2782 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2783 const char* subject_end = subject_start + subject.length();
2784 const char* pos = subject_start;
2785 while (limit > 0) {
2786 pos = reinterpret_cast<const char*>(
2787 memchr(pos, pattern, subject_end - pos));
2788 if (pos == NULL) return;
2789 indices->Add(static_cast<int>(pos - subject_start));
2790 pos++;
2791 limit--;
2792 }
2793}
2794
2795
2796template <typename SubjectChar, typename PatternChar>
2797void FindStringIndices(Isolate* isolate,
2798 Vector<const SubjectChar> subject,
2799 Vector<const PatternChar> pattern,
2800 ZoneList<int>* indices,
2801 unsigned int limit) {
2802 ASSERT(limit > 0);
2803 // Collect indices of pattern in subject.
2804 // Stop after finding at most limit values.
2805 int pattern_length = pattern.length();
2806 int index = 0;
2807 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2808 while (limit > 0) {
2809 index = search.Search(subject, index);
2810 if (index < 0) return;
2811 indices->Add(index);
2812 index += pattern_length;
2813 limit--;
2814 }
2815}
2816
2817
2818void FindStringIndicesDispatch(Isolate* isolate,
2819 String* subject,
2820 String* pattern,
2821 ZoneList<int>* indices,
2822 unsigned int limit) {
2823 {
2824 AssertNoAllocation no_gc;
2825 String::FlatContent subject_content = subject->GetFlatContent();
2826 String::FlatContent pattern_content = pattern->GetFlatContent();
2827 ASSERT(subject_content.IsFlat());
2828 ASSERT(pattern_content.IsFlat());
2829 if (subject_content.IsAscii()) {
2830 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2831 if (pattern_content.IsAscii()) {
2832 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2833 if (pattern_vector.length() == 1) {
2834 FindAsciiStringIndices(subject_vector,
2835 pattern_vector[0],
2836 indices,
2837 limit);
2838 } else {
2839 FindStringIndices(isolate,
2840 subject_vector,
2841 pattern_vector,
2842 indices,
2843 limit);
2844 }
2845 } else {
2846 FindStringIndices(isolate,
2847 subject_vector,
2848 pattern_content.ToUC16Vector(),
2849 indices,
2850 limit);
2851 }
2852 } else {
2853 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002854 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002855 FindStringIndices(isolate,
2856 subject_vector,
2857 pattern_content.ToAsciiVector(),
2858 indices,
2859 limit);
2860 } else {
2861 FindStringIndices(isolate,
2862 subject_vector,
2863 pattern_content.ToUC16Vector(),
2864 indices,
2865 limit);
2866 }
2867 }
2868 }
2869}
2870
2871
2872template<typename ResultSeqString>
2873MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2874 Isolate* isolate,
2875 Handle<String> subject,
2876 Handle<JSRegExp> pattern_regexp,
2877 Handle<String> replacement) {
2878 ASSERT(subject->IsFlat());
2879 ASSERT(replacement->IsFlat());
2880
2881 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2882 ZoneList<int> indices(8);
2883 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2884 String* pattern =
2885 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2886 int subject_len = subject->length();
2887 int pattern_len = pattern->length();
2888 int replacement_len = replacement->length();
2889
2890 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2891
2892 int matches = indices.length();
2893 if (matches == 0) return *subject;
2894
2895 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2896 int subject_pos = 0;
2897 int result_pos = 0;
2898
2899 Handle<ResultSeqString> result;
2900 if (ResultSeqString::kHasAsciiEncoding) {
2901 result = Handle<ResultSeqString>::cast(
2902 isolate->factory()->NewRawAsciiString(result_len));
2903 } else {
2904 result = Handle<ResultSeqString>::cast(
2905 isolate->factory()->NewRawTwoByteString(result_len));
2906 }
2907
2908 for (int i = 0; i < matches; i++) {
2909 // Copy non-matched subject content.
2910 if (subject_pos < indices.at(i)) {
2911 String::WriteToFlat(*subject,
2912 result->GetChars() + result_pos,
2913 subject_pos,
2914 indices.at(i));
2915 result_pos += indices.at(i) - subject_pos;
2916 }
2917
2918 // Replace match.
2919 if (replacement_len > 0) {
2920 String::WriteToFlat(*replacement,
2921 result->GetChars() + result_pos,
2922 0,
2923 replacement_len);
2924 result_pos += replacement_len;
2925 }
2926
2927 subject_pos = indices.at(i) + pattern_len;
2928 }
2929 // Add remaining subject content at the end.
2930 if (subject_pos < subject_len) {
2931 String::WriteToFlat(*subject,
2932 result->GetChars() + result_pos,
2933 subject_pos,
2934 subject_len);
2935 }
2936 return *result;
2937}
2938
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002939
lrn@chromium.org303ada72010-10-27 09:33:13 +00002940MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002941 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002942 String* subject,
2943 JSRegExp* regexp,
2944 String* replacement,
2945 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002946 ASSERT(subject->IsFlat());
2947 ASSERT(replacement->IsFlat());
2948
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002949 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002950
2951 int length = subject->length();
2952 Handle<String> subject_handle(subject);
2953 Handle<JSRegExp> regexp_handle(regexp);
2954 Handle<String> replacement_handle(replacement);
2955 Handle<JSArray> last_match_info_handle(last_match_info);
2956 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2957 subject_handle,
2958 0,
2959 last_match_info_handle);
2960 if (match.is_null()) {
2961 return Failure::Exception();
2962 }
2963 if (match->IsNull()) {
2964 return *subject_handle;
2965 }
2966
2967 int capture_count = regexp_handle->CaptureCount();
2968
2969 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002970 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002971 CompiledReplacement compiled_replacement;
2972 compiled_replacement.Compile(replacement_handle,
2973 capture_count,
2974 length);
2975
2976 bool is_global = regexp_handle->GetFlags().is_global();
2977
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002978 // Shortcut for simple non-regexp global replacements
2979 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002980 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002981 compiled_replacement.simple_hint()) {
2982 if (subject_handle->HasOnlyAsciiChars() &&
2983 replacement_handle->HasOnlyAsciiChars()) {
2984 return StringReplaceStringWithString<SeqAsciiString>(
2985 isolate, subject_handle, regexp_handle, replacement_handle);
2986 } else {
2987 return StringReplaceStringWithString<SeqTwoByteString>(
2988 isolate, subject_handle, regexp_handle, replacement_handle);
2989 }
2990 }
2991
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002992 // Guessing the number of parts that the final result string is built
2993 // from. Global regexps can match any number of times, so we guess
2994 // conservatively.
2995 int expected_parts =
2996 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002997 ReplacementStringBuilder builder(isolate->heap(),
2998 subject_handle,
2999 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003000
3001 // Index of end of last match.
3002 int prev = 0;
3003
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003004 // Number of parts added by compiled replacement plus preceeding
3005 // string and possibly suffix after last match. It is possible for
3006 // all components to use two elements when encoded as two smis.
3007 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003008 bool matched = true;
3009 do {
3010 ASSERT(last_match_info_handle->HasFastElements());
3011 // Increase the capacity of the builder before entering local handle-scope,
3012 // so its internal buffer can safely allocate a new handle if it grows.
3013 builder.EnsureCapacity(parts_added_per_loop);
3014
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003015 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003016 int start, end;
3017 {
3018 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003019 FixedArray* match_info_array =
3020 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003021
3022 ASSERT_EQ(capture_count * 2 + 2,
3023 RegExpImpl::GetLastCaptureCount(match_info_array));
3024 start = RegExpImpl::GetCapture(match_info_array, 0);
3025 end = RegExpImpl::GetCapture(match_info_array, 1);
3026 }
3027
3028 if (prev < start) {
3029 builder.AddSubjectSlice(prev, start);
3030 }
3031 compiled_replacement.Apply(&builder,
3032 start,
3033 end,
3034 last_match_info_handle);
3035 prev = end;
3036
3037 // Only continue checking for global regexps.
3038 if (!is_global) break;
3039
3040 // Continue from where the match ended, unless it was an empty match.
3041 int next = end;
3042 if (start == end) {
3043 next = end + 1;
3044 if (next > length) break;
3045 }
3046
3047 match = RegExpImpl::Exec(regexp_handle,
3048 subject_handle,
3049 next,
3050 last_match_info_handle);
3051 if (match.is_null()) {
3052 return Failure::Exception();
3053 }
3054 matched = !match->IsNull();
3055 } while (matched);
3056
3057 if (prev < length) {
3058 builder.AddSubjectSlice(prev, length);
3059 }
3060
3061 return *(builder.ToString());
3062}
3063
3064
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003065template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003066MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003067 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003068 String* subject,
3069 JSRegExp* regexp,
3070 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003071 ASSERT(subject->IsFlat());
3072
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003073 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003074
3075 Handle<String> subject_handle(subject);
3076 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003077
3078 // Shortcut for simple non-regexp global replacements
3079 if (regexp_handle->GetFlags().is_global() &&
3080 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3081 Handle<String> empty_string_handle(HEAP->empty_string());
3082 if (subject_handle->HasOnlyAsciiChars()) {
3083 return StringReplaceStringWithString<SeqAsciiString>(
3084 isolate, subject_handle, regexp_handle, empty_string_handle);
3085 } else {
3086 return StringReplaceStringWithString<SeqTwoByteString>(
3087 isolate, subject_handle, regexp_handle, empty_string_handle);
3088 }
3089 }
3090
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003091 Handle<JSArray> last_match_info_handle(last_match_info);
3092 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3093 subject_handle,
3094 0,
3095 last_match_info_handle);
3096 if (match.is_null()) return Failure::Exception();
3097 if (match->IsNull()) return *subject_handle;
3098
3099 ASSERT(last_match_info_handle->HasFastElements());
3100
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003101 int start, end;
3102 {
3103 AssertNoAllocation match_info_array_is_not_in_a_handle;
3104 FixedArray* match_info_array =
3105 FixedArray::cast(last_match_info_handle->elements());
3106
3107 start = RegExpImpl::GetCapture(match_info_array, 0);
3108 end = RegExpImpl::GetCapture(match_info_array, 1);
3109 }
3110
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003111 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003112 int new_length = length - (end - start);
3113 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003114 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003115 }
3116 Handle<ResultSeqString> answer;
3117 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003118 answer = Handle<ResultSeqString>::cast(
3119 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003120 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003121 answer = Handle<ResultSeqString>::cast(
3122 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003123 }
3124
3125 // If the regexp isn't global, only match once.
3126 if (!regexp_handle->GetFlags().is_global()) {
3127 if (start > 0) {
3128 String::WriteToFlat(*subject_handle,
3129 answer->GetChars(),
3130 0,
3131 start);
3132 }
3133 if (end < length) {
3134 String::WriteToFlat(*subject_handle,
3135 answer->GetChars() + start,
3136 end,
3137 length);
3138 }
3139 return *answer;
3140 }
3141
3142 int prev = 0; // Index of end of last match.
3143 int next = 0; // Start of next search (prev unless last match was empty).
3144 int position = 0;
3145
3146 do {
3147 if (prev < start) {
3148 // Add substring subject[prev;start] to answer string.
3149 String::WriteToFlat(*subject_handle,
3150 answer->GetChars() + position,
3151 prev,
3152 start);
3153 position += start - prev;
3154 }
3155 prev = end;
3156 next = end;
3157 // Continue from where the match ended, unless it was an empty match.
3158 if (start == end) {
3159 next++;
3160 if (next > length) break;
3161 }
3162 match = RegExpImpl::Exec(regexp_handle,
3163 subject_handle,
3164 next,
3165 last_match_info_handle);
3166 if (match.is_null()) return Failure::Exception();
3167 if (match->IsNull()) break;
3168
3169 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003170 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003171 {
3172 AssertNoAllocation match_info_array_is_not_in_a_handle;
3173 FixedArray* match_info_array =
3174 FixedArray::cast(last_match_info_handle->elements());
3175 start = RegExpImpl::GetCapture(match_info_array, 0);
3176 end = RegExpImpl::GetCapture(match_info_array, 1);
3177 }
3178 } while (true);
3179
3180 if (prev < length) {
3181 // Add substring subject[prev;length] to answer string.
3182 String::WriteToFlat(*subject_handle,
3183 answer->GetChars() + position,
3184 prev,
3185 length);
3186 position += length - prev;
3187 }
3188
3189 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003190 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003191 }
3192
3193 // Shorten string and fill
3194 int string_size = ResultSeqString::SizeFor(position);
3195 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3196 int delta = allocated_string_size - string_size;
3197
3198 answer->set_length(position);
3199 if (delta == 0) return *answer;
3200
3201 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003202 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003203 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003204 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003205 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003206
3207 return *answer;
3208}
3209
3210
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003211RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003212 ASSERT(args.length() == 4);
3213
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003214 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003215 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003216 Object* flat_subject;
3217 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3218 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3219 return maybe_flat_subject;
3220 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003221 }
3222 subject = String::cast(flat_subject);
3223 }
3224
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003225 CONVERT_ARG_CHECKED(String, replacement, 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003226 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003227 Object* flat_replacement;
3228 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3229 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3230 return maybe_flat_replacement;
3231 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003232 }
3233 replacement = String::cast(flat_replacement);
3234 }
3235
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003236 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3237 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003238
3239 ASSERT(last_match_info->HasFastElements());
3240
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003241 if (replacement->length() == 0) {
3242 if (subject->HasOnlyAsciiChars()) {
3243 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003244 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003245 } else {
3246 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003247 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003248 }
3249 }
3250
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003251 return StringReplaceRegExpWithString(isolate,
3252 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003253 regexp,
3254 replacement,
3255 last_match_info);
3256}
3257
3258
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003259Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3260 Handle<String> subject,
3261 Handle<String> search,
3262 Handle<String> replace,
3263 bool* found,
3264 int recursion_limit) {
3265 if (recursion_limit == 0) return Handle<String>::null();
3266 if (subject->IsConsString()) {
3267 ConsString* cons = ConsString::cast(*subject);
3268 Handle<String> first = Handle<String>(cons->first());
3269 Handle<String> second = Handle<String>(cons->second());
3270 Handle<String> new_first =
3271 StringReplaceOneCharWithString(isolate,
3272 first,
3273 search,
3274 replace,
3275 found,
3276 recursion_limit - 1);
3277 if (*found) return isolate->factory()->NewConsString(new_first, second);
3278 if (new_first.is_null()) return new_first;
3279
3280 Handle<String> new_second =
3281 StringReplaceOneCharWithString(isolate,
3282 second,
3283 search,
3284 replace,
3285 found,
3286 recursion_limit - 1);
3287 if (*found) return isolate->factory()->NewConsString(first, new_second);
3288 if (new_second.is_null()) return new_second;
3289
3290 return subject;
3291 } else {
3292 int index = StringMatch(isolate, subject, search, 0);
3293 if (index == -1) return subject;
3294 *found = true;
3295 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3296 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3297 Handle<String> second =
3298 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3299 return isolate->factory()->NewConsString(cons1, second);
3300 }
3301}
3302
3303
3304RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3305 ASSERT(args.length() == 3);
3306 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003307 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3308 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
3309 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003310
3311 // If the cons string tree is too deep, we simply abort the recursion and
3312 // retry with a flattened subject string.
3313 const int kRecursionLimit = 0x1000;
3314 bool found = false;
3315 Handle<String> result =
3316 Runtime::StringReplaceOneCharWithString(isolate,
3317 subject,
3318 search,
3319 replace,
3320 &found,
3321 kRecursionLimit);
3322 if (!result.is_null()) return *result;
3323 return *Runtime::StringReplaceOneCharWithString(isolate,
3324 FlattenGetString(subject),
3325 search,
3326 replace,
3327 &found,
3328 kRecursionLimit);
3329}
3330
3331
ager@chromium.org7c537e22008-10-16 08:43:32 +00003332// Perform string match of pattern on subject, starting at start index.
3333// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003334// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003335int Runtime::StringMatch(Isolate* isolate,
3336 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003337 Handle<String> pat,
3338 int start_index) {
3339 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003340 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003341
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003342 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003343 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003344
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003345 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003346 if (start_index + pattern_length > subject_length) return -1;
3347
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003348 if (!sub->IsFlat()) FlattenString(sub);
3349 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003350
ager@chromium.org7c537e22008-10-16 08:43:32 +00003351 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003352 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003353 String::FlatContent seq_sub = sub->GetFlatContent();
3354 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003355
ager@chromium.org7c537e22008-10-16 08:43:32 +00003356 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003357 if (seq_pat.IsAscii()) {
3358 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3359 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003360 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003361 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003362 pat_vector,
3363 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003364 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003365 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003366 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003367 pat_vector,
3368 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003369 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003370 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3371 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003372 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003373 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003374 pat_vector,
3375 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003376 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003377 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003378 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003379 pat_vector,
3380 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003381}
3382
3383
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003384RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003385 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003386 ASSERT(args.length() == 3);
3387
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003388 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3389 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003390
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003391 Object* index = args[2];
3392 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003393 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003394
ager@chromium.org870a0b62008-11-04 11:43:05 +00003395 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003396 int position =
3397 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003398 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003399}
3400
3401
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003402template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003403static int StringMatchBackwards(Vector<const schar> subject,
3404 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003405 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003406 int pattern_length = pattern.length();
3407 ASSERT(pattern_length >= 1);
3408 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003409
3410 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003411 for (int i = 0; i < pattern_length; i++) {
3412 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003413 if (c > String::kMaxAsciiCharCode) {
3414 return -1;
3415 }
3416 }
3417 }
3418
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003419 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003420 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003421 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003422 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003423 while (j < pattern_length) {
3424 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003425 break;
3426 }
3427 j++;
3428 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003429 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003430 return i;
3431 }
3432 }
3433 return -1;
3434}
3435
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003436RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003437 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003438 ASSERT(args.length() == 3);
3439
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003440 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3441 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003442
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003443 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003444 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003445 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003446
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003447 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003448 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003449
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003450 if (start_index + pat_length > sub_length) {
3451 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003452 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003453
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003454 if (pat_length == 0) {
3455 return Smi::FromInt(start_index);
3456 }
3457
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003458 if (!sub->IsFlat()) FlattenString(sub);
3459 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003460
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003461 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003462 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3463
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003464 String::FlatContent sub_content = sub->GetFlatContent();
3465 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003466
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003467 if (pat_content.IsAscii()) {
3468 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3469 if (sub_content.IsAscii()) {
3470 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003471 pat_vector,
3472 start_index);
3473 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003474 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003475 pat_vector,
3476 start_index);
3477 }
3478 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003479 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3480 if (sub_content.IsAscii()) {
3481 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003482 pat_vector,
3483 start_index);
3484 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003485 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003486 pat_vector,
3487 start_index);
3488 }
3489 }
3490
3491 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003492}
3493
3494
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003495RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003496 NoHandleAllocation ha;
3497 ASSERT(args.length() == 2);
3498
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003499 CONVERT_ARG_CHECKED(String, str1, 0);
3500 CONVERT_ARG_CHECKED(String, str2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003501
3502 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003503 int str1_length = str1->length();
3504 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003505
3506 // Decide trivial cases without flattening.
3507 if (str1_length == 0) {
3508 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3509 return Smi::FromInt(-str2_length);
3510 } else {
3511 if (str2_length == 0) return Smi::FromInt(str1_length);
3512 }
3513
3514 int end = str1_length < str2_length ? str1_length : str2_length;
3515
3516 // No need to flatten if we are going to find the answer on the first
3517 // character. At this point we know there is at least one character
3518 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003519 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003520 if (d != 0) return Smi::FromInt(d);
3521
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003522 str1->TryFlatten();
3523 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003524
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003525 StringInputBuffer& buf1 =
3526 *isolate->runtime_state()->string_locale_compare_buf1();
3527 StringInputBuffer& buf2 =
3528 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003529
3530 buf1.Reset(str1);
3531 buf2.Reset(str2);
3532
3533 for (int i = 0; i < end; i++) {
3534 uint16_t char1 = buf1.GetNext();
3535 uint16_t char2 = buf2.GetNext();
3536 if (char1 != char2) return Smi::FromInt(char1 - char2);
3537 }
3538
3539 return Smi::FromInt(str1_length - str2_length);
3540}
3541
3542
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003543RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003544 NoHandleAllocation ha;
3545 ASSERT(args.length() == 3);
3546
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003547 CONVERT_ARG_CHECKED(String, value, 0);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003548 int start, end;
3549 // We have a fast integer-only case here to avoid a conversion to double in
3550 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003551 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3552 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3553 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3554 start = from_number;
3555 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003556 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003557 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3558 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003559 start = FastD2I(from_number);
3560 end = FastD2I(to_number);
3561 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003562 RUNTIME_ASSERT(end >= start);
3563 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003564 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003565 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003566 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003567}
3568
3569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003570RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003571 ASSERT_EQ(3, args.length());
3572
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003573 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3574 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3575 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
ager@chromium.org41826e72009-03-30 13:30:57 +00003576 HandleScope handles;
3577
3578 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3579
3580 if (match.is_null()) {
3581 return Failure::Exception();
3582 }
3583 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003584 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003585 }
3586 int length = subject->length();
3587
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003588 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003589 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003590 int start;
3591 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003592 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003593 {
3594 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003595 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003596 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3597 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3598 }
3599 offsets.Add(start);
3600 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003601 if (start == end) if (++end > length) break;
3602 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003603 if (match.is_null()) {
3604 return Failure::Exception();
3605 }
3606 } while (!match->IsNull());
3607 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003608 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003609 Handle<String> substring = isolate->factory()->
3610 NewSubString(subject, offsets.at(0), offsets.at(1));
3611 elements->set(0, *substring);
3612 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003613 int from = offsets.at(i * 2);
3614 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003615 Handle<String> substring = isolate->factory()->
3616 NewProperSubString(subject, from, to);
3617 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003618 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003620 result->set_length(Smi::FromInt(matches));
3621 return *result;
3622}
3623
3624
lrn@chromium.org25156de2010-04-06 13:10:27 +00003625// Two smis before and after the match, for very long strings.
3626const int kMaxBuilderEntriesPerRegExpMatch = 5;
3627
3628
3629static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3630 Handle<JSArray> last_match_info,
3631 int match_start,
3632 int match_end) {
3633 // Fill last_match_info with a single capture.
3634 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3635 AssertNoAllocation no_gc;
3636 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3637 RegExpImpl::SetLastCaptureCount(elements, 2);
3638 RegExpImpl::SetLastInput(elements, *subject);
3639 RegExpImpl::SetLastSubject(elements, *subject);
3640 RegExpImpl::SetCapture(elements, 0, match_start);
3641 RegExpImpl::SetCapture(elements, 1, match_end);
3642}
3643
3644
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003645template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003646static bool SearchStringMultiple(Isolate* isolate,
3647 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003648 Vector<const PatternChar> pattern,
3649 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003650 FixedArrayBuilder* builder,
3651 int* match_pos) {
3652 int pos = *match_pos;
3653 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003654 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003655 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003656 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003657 while (pos <= max_search_start) {
3658 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3659 *match_pos = pos;
3660 return false;
3661 }
3662 // Position of end of previous match.
3663 int match_end = pos + pattern_length;
3664 int new_pos = search.Search(subject, match_end);
3665 if (new_pos >= 0) {
3666 // A match.
3667 if (new_pos > match_end) {
3668 ReplacementStringBuilder::AddSubjectSlice(builder,
3669 match_end,
3670 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003671 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003672 pos = new_pos;
3673 builder->Add(pattern_string);
3674 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003675 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003676 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003677 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003678
lrn@chromium.org25156de2010-04-06 13:10:27 +00003679 if (pos < max_search_start) {
3680 ReplacementStringBuilder::AddSubjectSlice(builder,
3681 pos + pattern_length,
3682 subject_length);
3683 }
3684 *match_pos = pos;
3685 return true;
3686}
3687
3688
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003689static bool SearchStringMultiple(Isolate* isolate,
3690 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003691 Handle<String> pattern,
3692 Handle<JSArray> last_match_info,
3693 FixedArrayBuilder* builder) {
3694 ASSERT(subject->IsFlat());
3695 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003696
3697 // Treating as if a previous match was before first character.
3698 int match_pos = -pattern->length();
3699
3700 for (;;) { // Break when search complete.
3701 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3702 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003703 String::FlatContent subject_content = subject->GetFlatContent();
3704 String::FlatContent pattern_content = pattern->GetFlatContent();
3705 if (subject_content.IsAscii()) {
3706 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3707 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003708 if (SearchStringMultiple(isolate,
3709 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003710 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003711 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003712 builder,
3713 &match_pos)) break;
3714 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003715 if (SearchStringMultiple(isolate,
3716 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003717 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003718 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003719 builder,
3720 &match_pos)) break;
3721 }
3722 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003723 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
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 }
3740 }
3741
3742 if (match_pos >= 0) {
3743 SetLastMatchInfoNoCaptures(subject,
3744 last_match_info,
3745 match_pos,
3746 match_pos + pattern->length());
3747 return true;
3748 }
3749 return false; // No matches at all.
3750}
3751
3752
3753static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003754 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003755 Handle<String> subject,
3756 Handle<JSRegExp> regexp,
3757 Handle<JSArray> last_match_array,
3758 FixedArrayBuilder* builder) {
3759 ASSERT(subject->IsFlat());
3760 int match_start = -1;
3761 int match_end = 0;
3762 int pos = 0;
3763 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3764 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3765
ulan@chromium.org812308e2012-02-29 15:58:45 +00003766 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003767 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003768 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003769 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003770
3771 for (;;) { // Break on failure, return on exception.
3772 RegExpImpl::IrregexpResult result =
3773 RegExpImpl::IrregexpExecOnce(regexp,
3774 subject,
3775 pos,
3776 register_vector);
3777 if (result == RegExpImpl::RE_SUCCESS) {
3778 match_start = register_vector[0];
3779 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3780 if (match_end < match_start) {
3781 ReplacementStringBuilder::AddSubjectSlice(builder,
3782 match_end,
3783 match_start);
3784 }
3785 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003786 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003787 if (!first) {
3788 builder->Add(*isolate->factory()->NewProperSubString(subject,
3789 match_start,
3790 match_end));
3791 } else {
3792 builder->Add(*isolate->factory()->NewSubString(subject,
3793 match_start,
3794 match_end));
3795 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003796 if (match_start != match_end) {
3797 pos = match_end;
3798 } else {
3799 pos = match_end + 1;
3800 if (pos > subject_length) break;
3801 }
3802 } else if (result == RegExpImpl::RE_FAILURE) {
3803 break;
3804 } else {
3805 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3806 return result;
3807 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003808 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003809 }
3810
3811 if (match_start >= 0) {
3812 if (match_end < subject_length) {
3813 ReplacementStringBuilder::AddSubjectSlice(builder,
3814 match_end,
3815 subject_length);
3816 }
3817 SetLastMatchInfoNoCaptures(subject,
3818 last_match_array,
3819 match_start,
3820 match_end);
3821 return RegExpImpl::RE_SUCCESS;
3822 } else {
3823 return RegExpImpl::RE_FAILURE; // No matches at all.
3824 }
3825}
3826
3827
3828static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003829 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003830 Handle<String> subject,
3831 Handle<JSRegExp> regexp,
3832 Handle<JSArray> last_match_array,
3833 FixedArrayBuilder* builder) {
3834
3835 ASSERT(subject->IsFlat());
3836 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3837 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3838
ulan@chromium.org812308e2012-02-29 15:58:45 +00003839 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003840 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003841
3842 RegExpImpl::IrregexpResult result =
3843 RegExpImpl::IrregexpExecOnce(regexp,
3844 subject,
3845 0,
3846 register_vector);
3847
3848 int capture_count = regexp->CaptureCount();
3849 int subject_length = subject->length();
3850
3851 // Position to search from.
3852 int pos = 0;
3853 // End of previous match. Differs from pos if match was empty.
3854 int match_end = 0;
3855 if (result == RegExpImpl::RE_SUCCESS) {
3856 // Need to keep a copy of the previous match for creating last_match_info
3857 // at the end, so we have two vectors that we swap between.
ulan@chromium.org812308e2012-02-29 15:58:45 +00003858 OffsetsVector registers2(required_registers, isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003859 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003860 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003861 do {
3862 int match_start = register_vector[0];
3863 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3864 if (match_end < match_start) {
3865 ReplacementStringBuilder::AddSubjectSlice(builder,
3866 match_end,
3867 match_start);
3868 }
3869 match_end = register_vector[1];
3870
3871 {
3872 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003873 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003874 // Arguments array to replace function is match, captures, index and
3875 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003876 Handle<FixedArray> elements =
3877 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003878 Handle<String> match;
3879 if (!first) {
3880 match = isolate->factory()->NewProperSubString(subject,
3881 match_start,
3882 match_end);
3883 } else {
3884 match = isolate->factory()->NewSubString(subject,
3885 match_start,
3886 match_end);
3887 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003888 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003889 for (int i = 1; i <= capture_count; i++) {
3890 int start = register_vector[i * 2];
3891 if (start >= 0) {
3892 int end = register_vector[i * 2 + 1];
3893 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003894 Handle<String> substring;
3895 if (!first) {
3896 substring = isolate->factory()->NewProperSubString(subject,
3897 start,
3898 end);
3899 } else {
3900 substring = isolate->factory()->NewSubString(subject, start, end);
3901 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003902 elements->set(i, *substring);
3903 } else {
3904 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003905 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003906 }
3907 }
3908 elements->set(capture_count + 1, Smi::FromInt(match_start));
3909 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003910 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003911 }
3912 // Swap register vectors, so the last successful match is in
3913 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003914 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003915 prev_register_vector = register_vector;
3916 register_vector = tmp;
3917
3918 if (match_end > match_start) {
3919 pos = match_end;
3920 } else {
3921 pos = match_end + 1;
3922 if (pos > subject_length) {
3923 break;
3924 }
3925 }
3926
3927 result = RegExpImpl::IrregexpExecOnce(regexp,
3928 subject,
3929 pos,
3930 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003931 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003932 } while (result == RegExpImpl::RE_SUCCESS);
3933
3934 if (result != RegExpImpl::RE_EXCEPTION) {
3935 // Finished matching, with at least one match.
3936 if (match_end < subject_length) {
3937 ReplacementStringBuilder::AddSubjectSlice(builder,
3938 match_end,
3939 subject_length);
3940 }
3941
3942 int last_match_capture_count = (capture_count + 1) * 2;
3943 int last_match_array_size =
3944 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3945 last_match_array->EnsureSize(last_match_array_size);
3946 AssertNoAllocation no_gc;
3947 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3948 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3949 RegExpImpl::SetLastSubject(elements, *subject);
3950 RegExpImpl::SetLastInput(elements, *subject);
3951 for (int i = 0; i < last_match_capture_count; i++) {
3952 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3953 }
3954 return RegExpImpl::RE_SUCCESS;
3955 }
3956 }
3957 // No matches at all, return failure or exception result directly.
3958 return result;
3959}
3960
3961
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003962RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003963 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003964 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003965
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003966 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003967 if (!subject->IsFlat()) FlattenString(subject);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003968 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
3969 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
3970 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003971
3972 ASSERT(last_match_info->HasFastElements());
3973 ASSERT(regexp->GetFlags().is_global());
3974 Handle<FixedArray> result_elements;
3975 if (result_array->HasFastElements()) {
3976 result_elements =
3977 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003978 }
3979 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003980 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003981 }
3982 FixedArrayBuilder builder(result_elements);
3983
3984 if (regexp->TypeTag() == JSRegExp::ATOM) {
3985 Handle<String> pattern(
3986 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003987 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003988 if (SearchStringMultiple(isolate, subject, pattern,
3989 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003990 return *builder.ToJSArray(result_array);
3991 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003992 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003993 }
3994
3995 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3996
3997 RegExpImpl::IrregexpResult result;
3998 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003999 result = SearchRegExpNoCaptureMultiple(isolate,
4000 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00004001 regexp,
4002 last_match_info,
4003 &builder);
4004 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004005 result = SearchRegExpMultiple(isolate,
4006 subject,
4007 regexp,
4008 last_match_info,
4009 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004010 }
4011 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004012 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004013 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4014 return Failure::Exception();
4015}
4016
4017
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004018RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 NoHandleAllocation ha;
4020 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004021 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004022 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004023
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004024 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004025 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004026 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004027 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004028 // Character array used for conversion.
4029 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004030 return isolate->heap()->
4031 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004032 }
4033 }
4034
4035 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004036 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004037 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004038 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004039 }
4040 if (isinf(value)) {
4041 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004042 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004043 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004044 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004045 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004046 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004047 MaybeObject* result =
4048 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004049 DeleteArray(str);
4050 return result;
4051}
4052
4053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004054RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004055 NoHandleAllocation ha;
4056 ASSERT(args.length() == 2);
4057
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004058 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004059 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004060 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004061 }
4062 if (isinf(value)) {
4063 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004064 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004065 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004066 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004067 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004068 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 int f = FastD2I(f_number);
4070 RUNTIME_ASSERT(f >= 0);
4071 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004072 MaybeObject* res =
4073 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004074 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004075 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004076}
4077
4078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004079RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004080 NoHandleAllocation ha;
4081 ASSERT(args.length() == 2);
4082
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004083 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004085 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004086 }
4087 if (isinf(value)) {
4088 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004089 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004090 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004091 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004092 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004093 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004094 int f = FastD2I(f_number);
4095 RUNTIME_ASSERT(f >= -1 && f <= 20);
4096 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004097 MaybeObject* res =
4098 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004099 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004100 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004101}
4102
4103
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004104RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004105 NoHandleAllocation ha;
4106 ASSERT(args.length() == 2);
4107
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004108 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004110 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111 }
4112 if (isinf(value)) {
4113 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004114 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004115 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004116 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004117 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004118 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119 int f = FastD2I(f_number);
4120 RUNTIME_ASSERT(f >= 1 && f <= 21);
4121 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004122 MaybeObject* res =
4123 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004124 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004125 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126}
4127
4128
4129// Returns a single character string where first character equals
4130// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004131static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004132 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004133 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004134 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004135 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004136 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004137 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004138}
4139
4140
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004141MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4142 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004143 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004144 // Handle [] indexing on Strings
4145 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004146 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4147 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004148 }
4149
4150 // Handle [] indexing on String objects
4151 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004152 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4153 Handle<Object> result =
4154 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4155 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004156 }
4157
4158 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004159 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004160 }
4161
4162 return object->GetElement(index);
4163}
4164
4165
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004166MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4167 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004168 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004169 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004170
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004171 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004172 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004173 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004174 isolate->factory()->NewTypeError("non_object_property_load",
4175 HandleVector(args, 2));
4176 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004177 }
4178
4179 // Check if the given key is an array index.
4180 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004181 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004182 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004183 }
4184
4185 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004186 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004187 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004188 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004189 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190 bool has_pending_exception = false;
4191 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004192 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004193 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004194 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004195 }
4196
ager@chromium.org32912102009-01-16 10:38:43 +00004197 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004198 // the element if so.
4199 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004200 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004202 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004203 }
4204}
4205
4206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004207RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004208 NoHandleAllocation ha;
4209 ASSERT(args.length() == 2);
4210
4211 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004212 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004213
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004214 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004215}
4216
4217
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004218// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004219RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004220 NoHandleAllocation ha;
4221 ASSERT(args.length() == 2);
4222
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004223 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004224 // itself.
4225 //
4226 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004227 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004228 // global proxy object never has properties. This is the case
4229 // because the global proxy object forwards everything to its hidden
4230 // prototype including local lookups.
4231 //
4232 // Additionally, we need to make sure that we do not cache results
4233 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004234 if (args[0]->IsJSObject()) {
4235 if (!args[0]->IsJSGlobalProxy() &&
4236 !args[0]->IsAccessCheckNeeded() &&
4237 args[1]->IsString()) {
4238 JSObject* receiver = JSObject::cast(args[0]);
4239 String* key = String::cast(args[1]);
4240 if (receiver->HasFastProperties()) {
4241 // Attempt to use lookup cache.
4242 Map* receiver_map = receiver->map();
4243 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4244 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4245 if (offset != -1) {
4246 Object* value = receiver->FastPropertyAt(offset);
4247 return value->IsTheHole()
4248 ? isolate->heap()->undefined_value()
4249 : value;
4250 }
4251 // Lookup cache miss. Perform lookup and update the cache if
4252 // appropriate.
4253 LookupResult result(isolate);
4254 receiver->LocalLookup(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004255 if (result.IsFound() && result.type() == FIELD) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004256 int offset = result.GetFieldIndex();
4257 keyed_lookup_cache->Update(receiver_map, key, offset);
4258 return receiver->FastPropertyAt(offset);
4259 }
4260 } else {
4261 // Attempt dictionary lookup.
4262 StringDictionary* dictionary = receiver->property_dictionary();
4263 int entry = dictionary->FindEntry(key);
4264 if ((entry != StringDictionary::kNotFound) &&
4265 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4266 Object* value = dictionary->ValueAt(entry);
4267 if (!receiver->IsGlobalObject()) return value;
4268 value = JSGlobalPropertyCell::cast(value)->value();
4269 if (!value->IsTheHole()) return value;
4270 // If value is the hole do the general lookup.
4271 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004272 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004273 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4274 // JSObject without a string key. If the key is a Smi, check for a
4275 // definite out-of-bounds access to elements, which is a strong indicator
4276 // that subsequent accesses will also call the runtime. Proactively
4277 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4278 // doubles for those future calls in the case that the elements would
4279 // become FAST_DOUBLE_ELEMENTS.
4280 Handle<JSObject> js_object(args.at<JSObject>(0));
4281 ElementsKind elements_kind = js_object->GetElementsKind();
4282 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4283 elements_kind == FAST_DOUBLE_ELEMENTS) {
4284 FixedArrayBase* elements = js_object->elements();
4285 if (args.at<Smi>(1)->value() >= elements->length()) {
4286 MaybeObject* maybe_object = TransitionElements(js_object,
4287 FAST_ELEMENTS,
4288 isolate);
4289 if (maybe_object->IsFailure()) return maybe_object;
4290 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004291 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004292 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004293 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4294 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004295 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004296 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004297 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004298 if (index >= 0 && index < str->length()) {
4299 Handle<Object> result = GetCharAt(str, index);
4300 return *result;
4301 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004302 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004303
4304 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004305 return Runtime::GetObjectProperty(isolate,
4306 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004307 args.at<Object>(1));
4308}
4309
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004310// Implements part of 8.12.9 DefineOwnProperty.
4311// There are 3 cases that lead here:
4312// Step 4b - define a new accessor property.
4313// Steps 9c & 12 - replace an existing data property with an accessor property.
4314// Step 12 - update an existing accessor property with an accessor or generic
4315// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004316RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004317 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004318 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004319 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
4320 CONVERT_ARG_CHECKED(String, name, 1);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004321 CONVERT_SMI_ARG_CHECKED(flag, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004322 Object* fun = args[3];
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004323 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004324
ager@chromium.org5c838252010-02-19 08:53:10 +00004325 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004326 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004327
4328 RUNTIME_ASSERT(!obj->IsNull());
4329 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004330 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
4331 return obj->DefineAccessor(name, component, fun, attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004332}
4333
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004334// Implements part of 8.12.9 DefineOwnProperty.
4335// There are 3 cases that lead here:
4336// Step 4a - define a new data property.
4337// Steps 9b & 12 - replace an existing accessor property with a data property.
4338// Step 12 - update an existing data property with a data or generic
4339// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004340RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004341 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004342 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004343 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
4344 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00004345 Handle<Object> obj_value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004346 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004347
ager@chromium.org5c838252010-02-19 08:53:10 +00004348 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004349 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4350
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004351 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004352 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004353
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004354 // Special case for callback properties.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004355 if (result.IsFound() && result.type() == CALLBACKS) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004356 Object* callback = result.GetCallbackObject();
4357 // To be compatible with Safari we do not change the value on API objects
4358 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4359 // the value.
4360 if (callback->IsAccessorInfo()) {
4361 return isolate->heap()->undefined_value();
4362 }
4363 // Avoid redefining foreign callback as data property, just use the stored
4364 // setter to update the value instead.
4365 // TODO(mstarzinger): So far this only works if property attributes don't
4366 // change, this should be fixed once we cleanup the underlying code.
4367 if (callback->IsForeign() && result.GetAttributes() == attr) {
4368 return js_object->SetPropertyWithCallback(callback,
4369 *name,
4370 *obj_value,
4371 result.holder(),
4372 kStrictMode);
4373 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004374 }
4375
ager@chromium.org5c838252010-02-19 08:53:10 +00004376 // Take special care when attributes are different and there is already
4377 // a property. For simplicity we normalize the property which enables us
4378 // to not worry about changing the instance_descriptor and creating a new
4379 // map. The current version of SetObjectProperty does not handle attributes
4380 // correctly in the case where a property is a field and is reset with
4381 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004382 if (result.IsProperty() &&
4383 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004384 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004385 if (js_object->IsJSGlobalProxy()) {
4386 // Since the result is a property, the prototype will exist so
4387 // we don't have to check for null.
4388 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004389 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004390 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004391 // Use IgnoreAttributes version since a readonly property may be
4392 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004393 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4394 *obj_value,
4395 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004396 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004397
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004398 return Runtime::ForceSetObjectProperty(isolate,
4399 js_object,
4400 name,
4401 obj_value,
4402 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004403}
4404
4405
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004406MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4407 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004408 Handle<Object> key,
4409 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004410 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004411 StrictModeFlag strict_mode) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004412 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004413 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004414
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004415 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004416 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004417 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004418 isolate->factory()->NewTypeError("non_object_property_store",
4419 HandleVector(args, 2));
4420 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004421 }
4422
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004423 if (object->IsJSProxy()) {
4424 bool has_pending_exception = false;
4425 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4426 if (has_pending_exception) return Failure::Exception();
4427 return JSProxy::cast(*object)->SetProperty(
4428 String::cast(*name), *value, attr, strict_mode);
4429 }
4430
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004431 // If the object isn't a JavaScript object, we ignore the store.
4432 if (!object->IsJSObject()) return *value;
4433
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004434 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4435
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004436 // Check if the given key is an array index.
4437 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004438 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004439 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4440 // of a string using [] notation. We need to support this too in
4441 // JavaScript.
4442 // In the case of a String object we just need to redirect the assignment to
4443 // the underlying string if the index is in range. Since the underlying
4444 // string does nothing with the assignment then we can ignore such
4445 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004446 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004447 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004448 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004449
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004450 Handle<Object> result = JSObject::SetElement(
4451 js_object, index, value, attr, strict_mode, set_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004452 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004453 return *value;
4454 }
4455
4456 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004457 Handle<Object> result;
4458 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004459 result = JSObject::SetElement(
4460 js_object, index, value, attr, strict_mode, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004461 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004462 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004463 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004464 result = JSReceiver::SetProperty(
4465 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004466 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004467 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004468 return *value;
4469 }
4470
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004471 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004472 bool has_pending_exception = false;
4473 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4474 if (has_pending_exception) return Failure::Exception();
4475 Handle<String> name = Handle<String>::cast(converted);
4476
4477 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004478 return js_object->SetElement(
4479 index, *value, attr, strict_mode, true, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004480 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004481 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004482 }
4483}
4484
4485
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004486MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4487 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004488 Handle<Object> key,
4489 Handle<Object> value,
4490 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004491 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004492
4493 // Check if the given key is an array index.
4494 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004495 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004496 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4497 // of a string using [] notation. We need to support this too in
4498 // JavaScript.
4499 // In the case of a String object we just need to redirect the assignment to
4500 // the underlying string if the index is in range. Since the underlying
4501 // string does nothing with the assignment then we can ignore such
4502 // assignments.
4503 if (js_object->IsStringObjectWithCharacterAt(index)) {
4504 return *value;
4505 }
4506
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004507 return js_object->SetElement(
4508 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004509 }
4510
4511 if (key->IsString()) {
4512 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004513 return js_object->SetElement(
4514 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004515 } else {
4516 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004517 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004518 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4519 *value,
4520 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004521 }
4522 }
4523
4524 // Call-back into JavaScript to convert the key to a string.
4525 bool has_pending_exception = false;
4526 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4527 if (has_pending_exception) return Failure::Exception();
4528 Handle<String> name = Handle<String>::cast(converted);
4529
4530 if (name->AsArrayIndex(&index)) {
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 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004534 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004535 }
4536}
4537
4538
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004539MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004540 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004541 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004542 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004543
4544 // Check if the given key is an array index.
4545 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004546 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004547 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4548 // characters of a string using [] notation. In the case of a
4549 // String object we just need to redirect the deletion to the
4550 // underlying string if the index is in range. Since the
4551 // underlying string does nothing with the deletion, we can ignore
4552 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004553 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004554 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004555 }
4556
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004557 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004558 }
4559
4560 Handle<String> key_string;
4561 if (key->IsString()) {
4562 key_string = Handle<String>::cast(key);
4563 } else {
4564 // Call-back into JavaScript to convert the key to a string.
4565 bool has_pending_exception = false;
4566 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4567 if (has_pending_exception) return Failure::Exception();
4568 key_string = Handle<String>::cast(converted);
4569 }
4570
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004571 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004572 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004573}
4574
4575
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004576RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004577 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004578 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004579
4580 Handle<Object> object = args.at<Object>(0);
4581 Handle<Object> key = args.at<Object>(1);
4582 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004583 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004584 RUNTIME_ASSERT(
4585 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004586 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004587 PropertyAttributes attributes =
4588 static_cast<PropertyAttributes>(unchecked_attributes);
4589
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004590 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004591 if (args.length() == 5) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004592 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004593 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004594 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004595
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004596 return Runtime::SetObjectProperty(isolate,
4597 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004598 key,
4599 value,
4600 attributes,
4601 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004602}
4603
4604
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004605RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4606 NoHandleAllocation ha;
4607 RUNTIME_ASSERT(args.length() == 1);
4608 Handle<Object> object = args.at<Object>(0);
4609 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4610}
4611
4612
4613RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4614 NoHandleAllocation ha;
4615 RUNTIME_ASSERT(args.length() == 1);
4616 Handle<Object> object = args.at<Object>(0);
4617 return TransitionElements(object, FAST_ELEMENTS, isolate);
4618}
4619
4620
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004621// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004622// This is used to decide if we should transform null and undefined
4623// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004624RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004625 NoHandleAllocation ha;
4626 RUNTIME_ASSERT(args.length() == 1);
4627
4628 Handle<Object> object = args.at<Object>(0);
4629
4630 if (object->IsJSFunction()) {
4631 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004632 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004633 }
4634 return isolate->heap()->undefined_value();
4635}
4636
4637
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004638RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4639 RUNTIME_ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004640 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004641 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4642 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004643 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004644 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4645 HandleScope scope;
4646
4647 Object* raw_boilerplate_object = literals->get(literal_index);
4648 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4649#if DEBUG
4650 ElementsKind elements_kind = object->GetElementsKind();
4651#endif
4652 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4653 // Smis should never trigger transitions.
4654 ASSERT(!value->IsSmi());
4655
4656 if (value->IsNumber()) {
4657 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004658 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4659 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004660 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4661 FixedDoubleArray* double_array =
4662 FixedDoubleArray::cast(object->elements());
4663 HeapNumber* number = HeapNumber::cast(*value);
4664 double_array->set(store_index, number->Number());
4665 } else {
4666 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4667 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004668 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4669 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004670 FixedArray* object_array =
4671 FixedArray::cast(object->elements());
4672 object_array->set(store_index, *value);
4673 }
4674 return *object;
4675}
4676
4677
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004678// Set a local property, even if it is READ_ONLY. If the property does not
4679// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004680RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004681 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004682 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004683 CONVERT_ARG_CHECKED(JSObject, object, 0);
4684 CONVERT_ARG_CHECKED(String, name, 1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004685 // Compute attributes.
4686 PropertyAttributes attributes = NONE;
4687 if (args.length() == 4) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004688 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004689 // Only attribute bits should be set.
4690 RUNTIME_ASSERT(
4691 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4692 attributes = static_cast<PropertyAttributes>(unchecked_value);
4693 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004694
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004695 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004696 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004697}
4698
4699
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004700RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004701 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004702 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004703
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004704 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4705 CONVERT_ARG_CHECKED(String, key, 1);
4706 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004707 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004708 ? JSReceiver::STRICT_DELETION
4709 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004710}
4711
4712
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004713static Object* HasLocalPropertyImplementation(Isolate* isolate,
4714 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004715 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004716 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004717 // Handle hidden prototypes. If there's a hidden prototype above this thing
4718 // then we have to check it for properties, because they are supposed to
4719 // look like they are on this object.
4720 Handle<Object> proto(object->GetPrototype());
4721 if (proto->IsJSObject() &&
4722 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004723 return HasLocalPropertyImplementation(isolate,
4724 Handle<JSObject>::cast(proto),
4725 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004726 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004727 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004728}
4729
4730
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004731RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004732 NoHandleAllocation ha;
4733 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004734 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004735
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004736 uint32_t index;
4737 const bool key_is_array_index = key->AsArrayIndex(&index);
4738
ager@chromium.org9085a012009-05-11 19:22:57 +00004739 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004740 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004741 if (obj->IsJSObject()) {
4742 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004743 // Fast case: either the key is a real named property or it is not
4744 // an array index and there are no interceptors or hidden
4745 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004746 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004747 Map* map = object->map();
4748 if (!key_is_array_index &&
4749 !map->has_named_interceptor() &&
4750 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4751 return isolate->heap()->false_value();
4752 }
4753 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004754 HandleScope scope(isolate);
4755 return HasLocalPropertyImplementation(isolate,
4756 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004757 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004758 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004759 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004760 String* string = String::cast(obj);
4761 if (index < static_cast<uint32_t>(string->length())) {
4762 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004763 }
4764 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004765 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004766}
4767
4768
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004769RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004770 NoHandleAllocation na;
4771 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004772 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4773 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004774
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004775 bool result = receiver->HasProperty(key);
4776 if (isolate->has_pending_exception()) return Failure::Exception();
4777 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004778}
4779
4780
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004781RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004782 NoHandleAllocation na;
4783 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004784 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4785 CONVERT_SMI_ARG_CHECKED(index, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004786
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004787 bool result = receiver->HasElement(index);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004788 if (isolate->has_pending_exception()) return Failure::Exception();
4789 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004790}
4791
4792
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004793RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004794 NoHandleAllocation ha;
4795 ASSERT(args.length() == 2);
4796
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004797 CONVERT_ARG_CHECKED(JSObject, object, 0);
4798 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004799
4800 uint32_t index;
4801 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004802 JSObject::LocalElementType type = object->HasLocalElement(index);
4803 switch (type) {
4804 case JSObject::UNDEFINED_ELEMENT:
4805 case JSObject::STRING_CHARACTER_ELEMENT:
4806 return isolate->heap()->false_value();
4807 case JSObject::INTERCEPTED_ELEMENT:
4808 case JSObject::FAST_ELEMENT:
4809 return isolate->heap()->true_value();
4810 case JSObject::DICTIONARY_ELEMENT: {
4811 if (object->IsJSGlobalProxy()) {
4812 Object* proto = object->GetPrototype();
4813 if (proto->IsNull()) {
4814 return isolate->heap()->false_value();
4815 }
4816 ASSERT(proto->IsJSGlobalObject());
4817 object = JSObject::cast(proto);
4818 }
4819 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004820 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004821 if (elements->map() ==
4822 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004823 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004824 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004825 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004826 }
4827 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004828 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004829 PropertyDetails details = dictionary->DetailsAt(entry);
4830 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4831 }
4832 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004833 }
4834
ager@chromium.org870a0b62008-11-04 11:43:05 +00004835 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004836 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004837}
4838
4839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004840RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004841 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004842 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004843 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004844 bool threw = false;
4845 Handle<JSArray> result = GetKeysFor(object, &threw);
4846 if (threw) return Failure::Exception();
4847 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004848}
4849
4850
4851// Returns either a FixedArray as Runtime_GetPropertyNames,
4852// or, if the given object has an enum cache that contains
4853// all enumerable properties of the object and its prototypes
4854// have none, the map of the object. This is used to speed up
4855// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004856RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004857 ASSERT(args.length() == 1);
4858
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004859 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004860
4861 if (raw_object->IsSimpleEnum()) return raw_object->map();
4862
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004863 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004864 Handle<JSReceiver> object(raw_object);
4865 bool threw = false;
4866 Handle<FixedArray> content =
4867 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4868 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004869
4870 // Test again, since cache may have been built by preceding call.
4871 if (object->IsSimpleEnum()) return object->map();
4872
4873 return *content;
4874}
4875
4876
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004877// Find the length of the prototype chain that is to to handled as one. If a
4878// prototype object is hidden it is to be viewed as part of the the object it
4879// is prototype for.
4880static int LocalPrototypeChainLength(JSObject* obj) {
4881 int count = 1;
4882 Object* proto = obj->GetPrototype();
4883 while (proto->IsJSObject() &&
4884 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4885 count++;
4886 proto = JSObject::cast(proto)->GetPrototype();
4887 }
4888 return count;
4889}
4890
4891
4892// Return the names of the local named properties.
4893// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004894RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004895 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004896 ASSERT(args.length() == 1);
4897 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004898 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004899 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004900 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004901
4902 // Skip the global proxy as it has no properties and always delegates to the
4903 // real global object.
4904 if (obj->IsJSGlobalProxy()) {
4905 // Only collect names if access is permitted.
4906 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004907 !isolate->MayNamedAccess(*obj,
4908 isolate->heap()->undefined_value(),
4909 v8::ACCESS_KEYS)) {
4910 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4911 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004912 }
4913 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4914 }
4915
4916 // Find the number of objects making up this.
4917 int length = LocalPrototypeChainLength(*obj);
4918
4919 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004920 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004921 int total_property_count = 0;
4922 Handle<JSObject> jsproto = obj;
4923 for (int i = 0; i < length; i++) {
4924 // Only collect names if access is permitted.
4925 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004926 !isolate->MayNamedAccess(*jsproto,
4927 isolate->heap()->undefined_value(),
4928 v8::ACCESS_KEYS)) {
4929 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4930 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004931 }
4932 int n;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004933 n = jsproto->NumberOfLocalProperties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004934 local_property_count[i] = n;
4935 total_property_count += n;
4936 if (i < length - 1) {
4937 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4938 }
4939 }
4940
4941 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004942 Handle<FixedArray> names =
4943 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004944
4945 // Get the property names.
4946 jsproto = obj;
4947 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004948 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004949 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004950 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4951 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004952 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004953 proto_with_hidden_properties++;
4954 }
4955 if (i < length - 1) {
4956 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4957 }
4958 }
4959
4960 // Filter out name of hidden propeties object.
4961 if (proto_with_hidden_properties > 0) {
4962 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004963 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004964 names->length() - proto_with_hidden_properties);
4965 int dest_pos = 0;
4966 for (int i = 0; i < total_property_count; i++) {
4967 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004968 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004969 continue;
4970 }
4971 names->set(dest_pos++, name);
4972 }
4973 }
4974
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004975 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004976}
4977
4978
4979// Return the names of the local indexed properties.
4980// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004981RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004982 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004983 ASSERT(args.length() == 1);
4984 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004985 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004986 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004987 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004988
4989 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004990 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004991 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004992 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004993}
4994
4995
4996// Return information on whether an object has a named or indexed interceptor.
4997// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004998RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004999 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005000 ASSERT(args.length() == 1);
5001 if (!args[0]->IsJSObject()) {
5002 return Smi::FromInt(0);
5003 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005004 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005005
5006 int result = 0;
5007 if (obj->HasNamedInterceptor()) result |= 2;
5008 if (obj->HasIndexedInterceptor()) result |= 1;
5009
5010 return Smi::FromInt(result);
5011}
5012
5013
5014// Return property names from named interceptor.
5015// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005016RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005017 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005018 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005019 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005020
5021 if (obj->HasNamedInterceptor()) {
5022 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5023 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5024 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005025 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005026}
5027
5028
5029// Return element names from indexed interceptor.
5030// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005031RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005032 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005033 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005034 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005035
5036 if (obj->HasIndexedInterceptor()) {
5037 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5038 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5039 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005040 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005041}
5042
5043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005044RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005045 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005046 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005047 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005048 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005049
5050 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005051 // Do access checks before going to the global object.
5052 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005053 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005054 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005055 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5056 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005057 }
5058
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005059 Handle<Object> proto(object->GetPrototype());
5060 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005061 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005062 object = Handle<JSObject>::cast(proto);
5063 }
5064
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005065 bool threw = false;
5066 Handle<FixedArray> contents =
5067 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5068 if (threw) return Failure::Exception();
5069
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005070 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5071 // property array and since the result is mutable we have to create
5072 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005073 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005074 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005075 for (int i = 0; i < length; i++) {
5076 Object* entry = contents->get(i);
5077 if (entry->IsString()) {
5078 copy->set(i, entry);
5079 } else {
5080 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005081 HandleScope scope(isolate);
5082 Handle<Object> entry_handle(entry, isolate);
5083 Handle<Object> entry_str =
5084 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005085 copy->set(i, *entry_str);
5086 }
5087 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005088 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005089}
5090
5091
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005092RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005093 NoHandleAllocation ha;
5094 ASSERT(args.length() == 1);
5095
5096 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005097 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005098 it.AdvanceToArgumentsFrame();
5099 JavaScriptFrame* frame = it.frame();
5100
5101 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005102 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005103
5104 // Try to convert the key to an index. If successful and within
5105 // index return the the argument from the frame.
5106 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005107 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005108 return frame->GetParameter(index);
5109 }
5110
5111 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005112 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005113 bool exception = false;
5114 Handle<Object> converted =
5115 Execution::ToString(args.at<Object>(0), &exception);
5116 if (exception) return Failure::Exception();
5117 Handle<String> key = Handle<String>::cast(converted);
5118
5119 // Try to convert the string key into an array index.
5120 if (key->AsArrayIndex(&index)) {
5121 if (index < n) {
5122 return frame->GetParameter(index);
5123 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005124 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005125 }
5126 }
5127
5128 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005129 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5130 if (key->Equals(isolate->heap()->callee_symbol())) {
5131 Object* function = frame->function();
5132 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005133 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005134 return isolate->Throw(*isolate->factory()->NewTypeError(
5135 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5136 }
5137 return function;
5138 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005139
5140 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005141 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005142}
5143
5144
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005145RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005146 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005147 Object* object = args[0];
5148 return (object->IsJSObject() && !object->IsGlobalObject())
5149 ? JSObject::cast(object)->TransformToFastProperties(0)
5150 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005151}
5152
5153
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005154RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005155 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005156 Object* obj = args[0];
5157 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5158 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5159 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005160}
5161
5162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005163RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005164 NoHandleAllocation ha;
5165 ASSERT(args.length() == 1);
5166
5167 return args[0]->ToBoolean();
5168}
5169
5170
5171// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5172// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005173RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005174 NoHandleAllocation ha;
5175
5176 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005177 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005178 HeapObject* heap_obj = HeapObject::cast(obj);
5179
5180 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005181 if (heap_obj->map()->is_undetectable()) {
5182 return isolate->heap()->undefined_symbol();
5183 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005184
5185 InstanceType instance_type = heap_obj->map()->instance_type();
5186 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005187 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005188 }
5189
5190 switch (instance_type) {
5191 case ODDBALL_TYPE:
5192 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005193 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005194 }
5195 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005196 return FLAG_harmony_typeof
5197 ? isolate->heap()->null_symbol()
5198 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005199 }
5200 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005201 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005202 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005203 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005204 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005205 default:
5206 // For any kind of object not handled above, the spec rule for
5207 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005208 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005209 }
5210}
5211
5212
lrn@chromium.org25156de2010-04-06 13:10:27 +00005213static bool AreDigits(const char*s, int from, int to) {
5214 for (int i = from; i < to; i++) {
5215 if (s[i] < '0' || s[i] > '9') return false;
5216 }
5217
5218 return true;
5219}
5220
5221
5222static int ParseDecimalInteger(const char*s, int from, int to) {
5223 ASSERT(to - from < 10); // Overflow is not possible.
5224 ASSERT(from < to);
5225 int d = s[from] - '0';
5226
5227 for (int i = from + 1; i < to; i++) {
5228 d = 10 * d + (s[i] - '0');
5229 }
5230
5231 return d;
5232}
5233
5234
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005235RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005236 NoHandleAllocation ha;
5237 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005238 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005239 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005240
5241 // Fast case: short integer or some sorts of junk values.
5242 int len = subject->length();
5243 if (subject->IsSeqAsciiString()) {
5244 if (len == 0) return Smi::FromInt(0);
5245
5246 char const* data = SeqAsciiString::cast(subject)->GetChars();
5247 bool minus = (data[0] == '-');
5248 int start_pos = (minus ? 1 : 0);
5249
5250 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005251 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005252 } else if (data[start_pos] > '9') {
5253 // Fast check for a junk value. A valid string may start from a
5254 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5255 // the 'I' character ('Infinity'). All of that have codes not greater than
5256 // '9' except 'I'.
5257 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005258 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005259 }
5260 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5261 // The maximal/minimal smi has 10 digits. If the string has less digits we
5262 // know it will fit into the smi-data type.
5263 int d = ParseDecimalInteger(data, start_pos, len);
5264 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005265 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005266 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005267 } else if (!subject->HasHashCode() &&
5268 len <= String::kMaxArrayIndexSize &&
5269 (len == 1 || data[0] != '0')) {
5270 // String hash is not calculated yet but all the data are present.
5271 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005272 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005273#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005274 subject->Hash(); // Force hash calculation.
5275 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5276 static_cast<int>(hash));
5277#endif
5278 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005279 }
5280 return Smi::FromInt(d);
5281 }
5282 }
5283
5284 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005285 return isolate->heap()->NumberFromDouble(
5286 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005287}
5288
5289
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005290RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005291 NoHandleAllocation ha;
5292 ASSERT(args.length() == 1);
5293
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005294 CONVERT_ARG_CHECKED(JSArray, codes, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005295 int length = Smi::cast(codes->length())->value();
5296
5297 // Check if the string can be ASCII.
5298 int i;
5299 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005300 Object* element;
5301 { MaybeObject* maybe_element = codes->GetElement(i);
5302 // We probably can't get an exception here, but just in order to enforce
5303 // the checking of inputs in the runtime calls we check here.
5304 if (!maybe_element->ToObject(&element)) return maybe_element;
5305 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005306 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5307 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5308 break;
5309 }
5310
lrn@chromium.org303ada72010-10-27 09:33:13 +00005311 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005312 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005313 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005314 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005315 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005316 }
5317
lrn@chromium.org303ada72010-10-27 09:33:13 +00005318 Object* object = NULL;
5319 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005320 String* result = String::cast(object);
5321 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005322 Object* element;
5323 { MaybeObject* maybe_element = codes->GetElement(i);
5324 if (!maybe_element->ToObject(&element)) return maybe_element;
5325 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005326 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005327 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005328 }
5329 return result;
5330}
5331
5332
5333// kNotEscaped is generated by the following:
5334//
5335// #!/bin/perl
5336// for (my $i = 0; $i < 256; $i++) {
5337// print "\n" if $i % 16 == 0;
5338// my $c = chr($i);
5339// my $escaped = 1;
5340// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5341// print $escaped ? "0, " : "1, ";
5342// }
5343
5344
5345static bool IsNotEscaped(uint16_t character) {
5346 // Only for 8 bit characters, the rest are always escaped (in a different way)
5347 ASSERT(character < 256);
5348 static const char kNotEscaped[256] = {
5349 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5350 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5351 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5352 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5353 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5354 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5355 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5356 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5357 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5358 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5359 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5360 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5361 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5362 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5364 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5365 };
5366 return kNotEscaped[character] != 0;
5367}
5368
5369
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005370RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005371 const char hex_chars[] = "0123456789ABCDEF";
5372 NoHandleAllocation ha;
5373 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005374 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005375
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005376 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005377
5378 int escaped_length = 0;
5379 int length = source->length();
5380 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005381 Access<StringInputBuffer> buffer(
5382 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005383 buffer->Reset(source);
5384 while (buffer->has_more()) {
5385 uint16_t character = buffer->GetNext();
5386 if (character >= 256) {
5387 escaped_length += 6;
5388 } else if (IsNotEscaped(character)) {
5389 escaped_length++;
5390 } else {
5391 escaped_length += 3;
5392 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005393 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005394 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005395 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005396 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005397 return Failure::OutOfMemoryException();
5398 }
5399 }
5400 }
5401 // No length change implies no change. Return original string if no change.
5402 if (escaped_length == length) {
5403 return source;
5404 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005405 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005406 { MaybeObject* maybe_o =
5407 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005408 if (!maybe_o->ToObject(&o)) return maybe_o;
5409 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005410 String* destination = String::cast(o);
5411 int dest_position = 0;
5412
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005413 Access<StringInputBuffer> buffer(
5414 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005415 buffer->Rewind();
5416 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005417 uint16_t chr = buffer->GetNext();
5418 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005419 destination->Set(dest_position, '%');
5420 destination->Set(dest_position+1, 'u');
5421 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5422 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5423 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5424 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005425 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005426 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005427 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005428 dest_position++;
5429 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005430 destination->Set(dest_position, '%');
5431 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5432 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005433 dest_position += 3;
5434 }
5435 }
5436 return destination;
5437}
5438
5439
5440static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5441 static const signed char kHexValue['g'] = {
5442 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5443 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5444 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5445 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5446 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5447 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5448 -1, 10, 11, 12, 13, 14, 15 };
5449
5450 if (character1 > 'f') return -1;
5451 int hi = kHexValue[character1];
5452 if (hi == -1) return -1;
5453 if (character2 > 'f') return -1;
5454 int lo = kHexValue[character2];
5455 if (lo == -1) return -1;
5456 return (hi << 4) + lo;
5457}
5458
5459
ager@chromium.org870a0b62008-11-04 11:43:05 +00005460static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005461 int i,
5462 int length,
5463 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005464 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005465 int32_t hi = 0;
5466 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005467 if (character == '%' &&
5468 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005469 source->Get(i + 1) == 'u' &&
5470 (hi = TwoDigitHex(source->Get(i + 2),
5471 source->Get(i + 3))) != -1 &&
5472 (lo = TwoDigitHex(source->Get(i + 4),
5473 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005474 *step = 6;
5475 return (hi << 8) + lo;
5476 } else if (character == '%' &&
5477 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005478 (lo = TwoDigitHex(source->Get(i + 1),
5479 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005480 *step = 3;
5481 return lo;
5482 } else {
5483 *step = 1;
5484 return character;
5485 }
5486}
5487
5488
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005489RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005490 NoHandleAllocation ha;
5491 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005492 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005493
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005494 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005495
5496 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005497 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005498
5499 int unescaped_length = 0;
5500 for (int i = 0; i < length; unescaped_length++) {
5501 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005502 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005503 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005504 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005505 i += step;
5506 }
5507
5508 // No length change implies no change. Return original string if no change.
5509 if (unescaped_length == length)
5510 return source;
5511
lrn@chromium.org303ada72010-10-27 09:33:13 +00005512 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005513 { MaybeObject* maybe_o =
5514 ascii ?
5515 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5516 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005517 if (!maybe_o->ToObject(&o)) return maybe_o;
5518 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005519 String* destination = String::cast(o);
5520
5521 int dest_position = 0;
5522 for (int i = 0; i < length; dest_position++) {
5523 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005524 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005525 i += step;
5526 }
5527 return destination;
5528}
5529
5530
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005531static const unsigned int kQuoteTableLength = 128u;
5532
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005533static const int kJsonQuotesCharactersPerEntry = 8;
5534static const char* const JsonQuotes =
5535 "\\u0000 \\u0001 \\u0002 \\u0003 "
5536 "\\u0004 \\u0005 \\u0006 \\u0007 "
5537 "\\b \\t \\n \\u000b "
5538 "\\f \\r \\u000e \\u000f "
5539 "\\u0010 \\u0011 \\u0012 \\u0013 "
5540 "\\u0014 \\u0015 \\u0016 \\u0017 "
5541 "\\u0018 \\u0019 \\u001a \\u001b "
5542 "\\u001c \\u001d \\u001e \\u001f "
5543 " ! \\\" # "
5544 "$ % & ' "
5545 "( ) * + "
5546 ", - . / "
5547 "0 1 2 3 "
5548 "4 5 6 7 "
5549 "8 9 : ; "
5550 "< = > ? "
5551 "@ A B C "
5552 "D E F G "
5553 "H I J K "
5554 "L M N O "
5555 "P Q R S "
5556 "T U V W "
5557 "X Y Z [ "
5558 "\\\\ ] ^ _ "
5559 "` a b c "
5560 "d e f g "
5561 "h i j k "
5562 "l m n o "
5563 "p q r s "
5564 "t u v w "
5565 "x y z { "
5566 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005567
5568
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005569// For a string that is less than 32k characters it should always be
5570// possible to allocate it in new space.
5571static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5572
5573
5574// Doing JSON quoting cannot make the string more than this many times larger.
5575static const int kJsonQuoteWorstCaseBlowup = 6;
5576
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005577static const int kSpaceForQuotesAndComma = 3;
5578static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005579
5580// Covers the entire ASCII range (all other characters are unchanged by JSON
5581// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005582static const byte JsonQuoteLengths[kQuoteTableLength] = {
5583 6, 6, 6, 6, 6, 6, 6, 6,
5584 2, 2, 2, 6, 2, 2, 6, 6,
5585 6, 6, 6, 6, 6, 6, 6, 6,
5586 6, 6, 6, 6, 6, 6, 6, 6,
5587 1, 1, 2, 1, 1, 1, 1, 1,
5588 1, 1, 1, 1, 1, 1, 1, 1,
5589 1, 1, 1, 1, 1, 1, 1, 1,
5590 1, 1, 1, 1, 1, 1, 1, 1,
5591 1, 1, 1, 1, 1, 1, 1, 1,
5592 1, 1, 1, 1, 1, 1, 1, 1,
5593 1, 1, 1, 1, 1, 1, 1, 1,
5594 1, 1, 1, 1, 2, 1, 1, 1,
5595 1, 1, 1, 1, 1, 1, 1, 1,
5596 1, 1, 1, 1, 1, 1, 1, 1,
5597 1, 1, 1, 1, 1, 1, 1, 1,
5598 1, 1, 1, 1, 1, 1, 1, 1,
5599};
5600
5601
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005602template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005603MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005604
5605
5606template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005607MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5608 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005609}
5610
5611
5612template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005613MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5614 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005615}
5616
5617
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005618template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005619static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5620 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005621 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005622 const Char* read_cursor = characters.start();
5623 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005624 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005625 int quoted_length = kSpaceForQuotes;
5626 while (read_cursor < end) {
5627 Char c = *(read_cursor++);
5628 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5629 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005630 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005631 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005632 }
5633 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005634 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5635 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005636 Object* new_object;
5637 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005638 return new_alloc;
5639 }
5640 StringType* new_string = StringType::cast(new_object);
5641
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005642 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005643 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005644 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005645 *(write_cursor++) = '"';
5646
5647 read_cursor = characters.start();
5648 while (read_cursor < end) {
5649 Char c = *(read_cursor++);
5650 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5651 *(write_cursor++) = c;
5652 } else {
5653 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5654 const char* replacement = JsonQuotes +
5655 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5656 for (int i = 0; i < len; i++) {
5657 *write_cursor++ = *replacement++;
5658 }
5659 }
5660 }
5661 *(write_cursor++) = '"';
5662 return new_string;
5663}
5664
5665
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005666template <typename SinkChar, typename SourceChar>
5667static inline SinkChar* WriteQuoteJsonString(
5668 Isolate* isolate,
5669 SinkChar* write_cursor,
5670 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005671 // SinkChar is only char if SourceChar is guaranteed to be char.
5672 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005673 const SourceChar* read_cursor = characters.start();
5674 const SourceChar* end = read_cursor + characters.length();
5675 *(write_cursor++) = '"';
5676 while (read_cursor < end) {
5677 SourceChar c = *(read_cursor++);
5678 if (sizeof(SourceChar) > 1u &&
5679 static_cast<unsigned>(c) >= kQuoteTableLength) {
5680 *(write_cursor++) = static_cast<SinkChar>(c);
5681 } else {
5682 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5683 const char* replacement = JsonQuotes +
5684 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5685 write_cursor[0] = replacement[0];
5686 if (len > 1) {
5687 write_cursor[1] = replacement[1];
5688 if (len > 2) {
5689 ASSERT(len == 6);
5690 write_cursor[2] = replacement[2];
5691 write_cursor[3] = replacement[3];
5692 write_cursor[4] = replacement[4];
5693 write_cursor[5] = replacement[5];
5694 }
5695 }
5696 write_cursor += len;
5697 }
5698 }
5699 *(write_cursor++) = '"';
5700 return write_cursor;
5701}
5702
5703
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005704template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005705static MaybeObject* QuoteJsonString(Isolate* isolate,
5706 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005707 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005708 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005709 int worst_case_length =
5710 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005711 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005712 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005713 }
5714
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005715 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5716 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005717 Object* new_object;
5718 if (!new_alloc->ToObject(&new_object)) {
5719 return new_alloc;
5720 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005721 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005722 // Even if our string is small enough to fit in new space we still have to
5723 // handle it being allocated in old space as may happen in the third
5724 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5725 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005726 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005727 }
5728 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005729 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005730
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005731 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005732 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005733 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005734 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5735 write_cursor,
5736 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005737 int final_length = static_cast<int>(
5738 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005739 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005740 isolate->heap()->new_space()->
5741 template ShrinkStringAtAllocationBoundary<StringType>(
5742 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005743 return new_string;
5744}
5745
5746
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005747RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005748 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005749 CONVERT_ARG_CHECKED(String, str, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005750 if (!str->IsFlat()) {
5751 MaybeObject* try_flatten = str->TryFlatten();
5752 Object* flat;
5753 if (!try_flatten->ToObject(&flat)) {
5754 return try_flatten;
5755 }
5756 str = String::cast(flat);
5757 ASSERT(str->IsFlat());
5758 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005759 String::FlatContent flat = str->GetFlatContent();
5760 ASSERT(flat.IsFlat());
5761 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005762 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005763 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005764 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005765 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005766 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005767 }
5768}
5769
5770
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005771RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005772 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005773 CONVERT_ARG_CHECKED(String, str, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005774 if (!str->IsFlat()) {
5775 MaybeObject* try_flatten = str->TryFlatten();
5776 Object* flat;
5777 if (!try_flatten->ToObject(&flat)) {
5778 return try_flatten;
5779 }
5780 str = String::cast(flat);
5781 ASSERT(str->IsFlat());
5782 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005783 String::FlatContent flat = str->GetFlatContent();
5784 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005785 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005786 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005787 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005788 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005789 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005790 }
5791}
5792
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005793
5794template <typename Char, typename StringType>
5795static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5796 FixedArray* array,
5797 int worst_case_length) {
5798 int length = array->length();
5799
5800 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5801 worst_case_length);
5802 Object* new_object;
5803 if (!new_alloc->ToObject(&new_object)) {
5804 return new_alloc;
5805 }
5806 if (!isolate->heap()->new_space()->Contains(new_object)) {
5807 // Even if our string is small enough to fit in new space we still have to
5808 // handle it being allocated in old space as may happen in the third
5809 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5810 // CEntryStub::GenerateCore.
5811 return isolate->heap()->undefined_value();
5812 }
5813 AssertNoAllocation no_gc;
5814 StringType* new_string = StringType::cast(new_object);
5815 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5816
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005817 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005818 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005819 *(write_cursor++) = '[';
5820 for (int i = 0; i < length; i++) {
5821 if (i != 0) *(write_cursor++) = ',';
5822 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005823 String::FlatContent content = str->GetFlatContent();
5824 ASSERT(content.IsFlat());
5825 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005826 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5827 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005828 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005829 } else {
5830 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5831 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005832 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005833 }
5834 }
5835 *(write_cursor++) = ']';
5836
5837 int final_length = static_cast<int>(
5838 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005839 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005840 isolate->heap()->new_space()->
5841 template ShrinkStringAtAllocationBoundary<StringType>(
5842 new_string, final_length);
5843 return new_string;
5844}
5845
5846
5847RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5848 NoHandleAllocation ha;
5849 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005850 CONVERT_ARG_CHECKED(JSArray, array, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005851
5852 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5853 FixedArray* elements = FixedArray::cast(array->elements());
5854 int n = elements->length();
5855 bool ascii = true;
5856 int total_length = 0;
5857
5858 for (int i = 0; i < n; i++) {
5859 Object* elt = elements->get(i);
5860 if (!elt->IsString()) return isolate->heap()->undefined_value();
5861 String* element = String::cast(elt);
5862 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5863 total_length += element->length();
5864 if (ascii && element->IsTwoByteRepresentation()) {
5865 ascii = false;
5866 }
5867 }
5868
5869 int worst_case_length =
5870 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5871 + total_length * kJsonQuoteWorstCaseBlowup;
5872
5873 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5874 return isolate->heap()->undefined_value();
5875 }
5876
5877 if (ascii) {
5878 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5879 elements,
5880 worst_case_length);
5881 } else {
5882 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5883 elements,
5884 worst_case_length);
5885 }
5886}
5887
5888
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005889RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005890 NoHandleAllocation ha;
5891
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005892 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005893 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005894
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005895 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005896
lrn@chromium.org25156de2010-04-06 13:10:27 +00005897 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005898 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005899 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005900}
5901
5902
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005903RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005904 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005905 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005906
5907 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005908 double value = StringToDouble(isolate->unicode_cache(),
5909 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005910
5911 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005912 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005913}
5914
5915
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005916template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005917MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005918 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005919 String* s,
5920 int length,
5921 int input_string_length,
5922 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005923 // We try this twice, once with the assumption that the result is no longer
5924 // than the input and, if that assumption breaks, again with the exact
5925 // length. This may not be pretty, but it is nicer than what was here before
5926 // and I hereby claim my vaffel-is.
5927 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005928 // Allocate the resulting string.
5929 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005930 // NOTE: This assumes that the upper/lower case of an ASCII
5931 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005932 // might break in the future if we implement more context and locale
5933 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005934 Object* o;
5935 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005936 ? isolate->heap()->AllocateRawAsciiString(length)
5937 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005938 if (!maybe_o->ToObject(&o)) return maybe_o;
5939 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005940 String* result = String::cast(o);
5941 bool has_changed_character = false;
5942
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005943 // Convert all characters to upper case, assuming that they will fit
5944 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005945 Access<StringInputBuffer> buffer(
5946 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005947 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005948 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005949 // We can assume that the string is not empty
5950 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005951 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005952 bool has_next = buffer->has_more();
5953 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005954 int char_length = mapping->get(current, next, chars);
5955 if (char_length == 0) {
5956 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005957 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005958 i++;
5959 } else if (char_length == 1) {
5960 // Common case: converting the letter resulted in one character.
5961 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005962 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005963 has_changed_character = true;
5964 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005965 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005966 // We've assumed that the result would be as long as the
5967 // input but here is a character that converts to several
5968 // characters. No matter, we calculate the exact length
5969 // of the result and try the whole thing again.
5970 //
5971 // Note that this leaves room for optimization. We could just
5972 // memcpy what we already have to the result string. Also,
5973 // the result string is the last object allocated we could
5974 // "realloc" it and probably, in the vast majority of cases,
5975 // extend the existing string to be able to hold the full
5976 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005977 int next_length = 0;
5978 if (has_next) {
5979 next_length = mapping->get(next, 0, chars);
5980 if (next_length == 0) next_length = 1;
5981 }
5982 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005983 while (buffer->has_more()) {
5984 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005985 // NOTE: we use 0 as the next character here because, while
5986 // the next character may affect what a character converts to,
5987 // it does not in any case affect the length of what it convert
5988 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005989 int char_length = mapping->get(current, 0, chars);
5990 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005991 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005992 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005993 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005994 return Failure::OutOfMemoryException();
5995 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005996 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005997 // Try again with the real length.
5998 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005999 } else {
6000 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006001 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006002 i++;
6003 }
6004 has_changed_character = true;
6005 }
6006 current = next;
6007 }
6008 if (has_changed_character) {
6009 return result;
6010 } else {
6011 // If we didn't actually change anything in doing the conversion
6012 // we simple return the result and let the converted string
6013 // become garbage; there is no reason to keep two identical strings
6014 // alive.
6015 return s;
6016 }
6017}
6018
6019
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006020namespace {
6021
lrn@chromium.org303ada72010-10-27 09:33:13 +00006022static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6023
6024
6025// Given a word and two range boundaries returns a word with high bit
6026// set in every byte iff the corresponding input byte was strictly in
6027// the range (m, n). All the other bits in the result are cleared.
6028// This function is only useful when it can be inlined and the
6029// boundaries are statically known.
6030// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006031// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006032static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006033 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006034 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6035 // Use strict inequalities since in edge cases the function could be
6036 // further simplified.
6037 ASSERT(0 < m && m < n && n < 0x7F);
6038 // Has high bit set in every w byte less than n.
6039 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6040 // Has high bit set in every w byte greater than m.
6041 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6042 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6043}
6044
6045
6046enum AsciiCaseConversion {
6047 ASCII_TO_LOWER,
6048 ASCII_TO_UPPER
6049};
6050
6051
6052template <AsciiCaseConversion dir>
6053struct FastAsciiConverter {
6054 static bool Convert(char* dst, char* src, int length) {
6055#ifdef DEBUG
6056 char* saved_dst = dst;
6057 char* saved_src = src;
6058#endif
6059 // We rely on the distance between upper and lower case letters
6060 // being a known power of 2.
6061 ASSERT('a' - 'A' == (1 << 5));
6062 // Boundaries for the range of input characters than require conversion.
6063 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6064 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6065 bool changed = false;
6066 char* const limit = src + length;
6067#ifdef V8_HOST_CAN_READ_UNALIGNED
6068 // Process the prefix of the input that requires no conversion one
6069 // (machine) word at a time.
6070 while (src <= limit - sizeof(uintptr_t)) {
6071 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6072 if (AsciiRangeMask(w, lo, hi) != 0) {
6073 changed = true;
6074 break;
6075 }
6076 *reinterpret_cast<uintptr_t*>(dst) = w;
6077 src += sizeof(uintptr_t);
6078 dst += sizeof(uintptr_t);
6079 }
6080 // Process the remainder of the input performing conversion when
6081 // required one word at a time.
6082 while (src <= limit - sizeof(uintptr_t)) {
6083 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6084 uintptr_t m = AsciiRangeMask(w, lo, hi);
6085 // The mask has high (7th) bit set in every byte that needs
6086 // conversion and we know that the distance between cases is
6087 // 1 << 5.
6088 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6089 src += sizeof(uintptr_t);
6090 dst += sizeof(uintptr_t);
6091 }
6092#endif
6093 // Process the last few bytes of the input (or the whole input if
6094 // unaligned access is not supported).
6095 while (src < limit) {
6096 char c = *src;
6097 if (lo < c && c < hi) {
6098 c ^= (1 << 5);
6099 changed = true;
6100 }
6101 *dst = c;
6102 ++src;
6103 ++dst;
6104 }
6105#ifdef DEBUG
6106 CheckConvert(saved_dst, saved_src, length, changed);
6107#endif
6108 return changed;
6109 }
6110
6111#ifdef DEBUG
6112 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6113 bool expected_changed = false;
6114 for (int i = 0; i < length; i++) {
6115 if (dst[i] == src[i]) continue;
6116 expected_changed = true;
6117 if (dir == ASCII_TO_LOWER) {
6118 ASSERT('A' <= src[i] && src[i] <= 'Z');
6119 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6120 } else {
6121 ASSERT(dir == ASCII_TO_UPPER);
6122 ASSERT('a' <= src[i] && src[i] <= 'z');
6123 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6124 }
6125 }
6126 ASSERT(expected_changed == changed);
6127 }
6128#endif
6129};
6130
6131
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006132struct ToLowerTraits {
6133 typedef unibrow::ToLowercase UnibrowConverter;
6134
lrn@chromium.org303ada72010-10-27 09:33:13 +00006135 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006136};
6137
6138
6139struct ToUpperTraits {
6140 typedef unibrow::ToUppercase UnibrowConverter;
6141
lrn@chromium.org303ada72010-10-27 09:33:13 +00006142 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006143};
6144
6145} // namespace
6146
6147
6148template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006149MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006150 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006151 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006152 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006153 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006154 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006155 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006156
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006157 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006158 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006159 if (length == 0) return s;
6160
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006161 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006162 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006163 // NOTE: This assumes that the upper/lower case of an ASCII
6164 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006165 // might break in the future if we implement more context and locale
6166 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006167 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006168 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006169 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006170 if (!maybe_o->ToObject(&o)) return maybe_o;
6171 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006172 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006173 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006174 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006175 return has_changed_character ? result : s;
6176 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006177
lrn@chromium.org303ada72010-10-27 09:33:13 +00006178 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006179 { MaybeObject* maybe_answer =
6180 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006181 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6182 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006183 if (answer->IsSmi()) {
6184 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006185 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006186 ConvertCaseHelper(isolate,
6187 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006188 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6189 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006190 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006191 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006192}
6193
6194
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006195RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006196 return ConvertCase<ToLowerTraits>(
6197 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006198}
6199
6200
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006201RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006202 return ConvertCase<ToUpperTraits>(
6203 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006204}
6205
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006206
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006207static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006208 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006209}
6210
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006212RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006213 NoHandleAllocation ha;
6214 ASSERT(args.length() == 3);
6215
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006216 CONVERT_ARG_CHECKED(String, s, 0);
6217 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6218 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006219
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006220 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006221 int length = s->length();
6222
6223 int left = 0;
6224 if (trimLeft) {
6225 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6226 left++;
6227 }
6228 }
6229
6230 int right = length;
6231 if (trimRight) {
6232 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6233 right--;
6234 }
6235 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006236 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006237}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006238
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006240RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006241 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006242 HandleScope handle_scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006243 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6244 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006245 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6246
6247 int subject_length = subject->length();
6248 int pattern_length = pattern->length();
6249 RUNTIME_ASSERT(pattern_length > 0);
6250
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006251 if (limit == 0xffffffffu) {
6252 Handle<Object> cached_answer(StringSplitCache::Lookup(
6253 isolate->heap()->string_split_cache(),
6254 *subject,
6255 *pattern));
6256 if (*cached_answer != Smi::FromInt(0)) {
6257 Handle<JSArray> result =
6258 isolate->factory()->NewJSArrayWithElements(
6259 Handle<FixedArray>::cast(cached_answer));
6260 return *result;
6261 }
6262 }
6263
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006264 // The limit can be very large (0xffffffffu), but since the pattern
6265 // isn't empty, we can never create more parts than ~half the length
6266 // of the subject.
6267
6268 if (!subject->IsFlat()) FlattenString(subject);
6269
6270 static const int kMaxInitialListCapacity = 16;
6271
danno@chromium.org40cb8782011-05-25 07:58:50 +00006272 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006273
6274 // Find (up to limit) indices of separator and end-of-string in subject
6275 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6276 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006277 if (!pattern->IsFlat()) FlattenString(pattern);
6278
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006279 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006280
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006281 if (static_cast<uint32_t>(indices.length()) < limit) {
6282 indices.Add(subject_length);
6283 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006284
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006285 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006286
6287 // Create JSArray of substrings separated by separator.
6288 int part_count = indices.length();
6289
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006290 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006291 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006292 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006293 result->set_length(Smi::FromInt(part_count));
6294
6295 ASSERT(result->HasFastElements());
6296
6297 if (part_count == 1 && indices.at(0) == subject_length) {
6298 FixedArray::cast(result->elements())->set(0, *subject);
6299 return *result;
6300 }
6301
6302 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6303 int part_start = 0;
6304 for (int i = 0; i < part_count; i++) {
6305 HandleScope local_loop_handle;
6306 int part_end = indices.at(i);
6307 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006308 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006309 elements->set(i, *substring);
6310 part_start = part_end + pattern_length;
6311 }
6312
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006313 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006314 if (result->HasFastElements()) {
6315 StringSplitCache::Enter(isolate->heap(),
6316 isolate->heap()->string_split_cache(),
6317 *subject,
6318 *pattern,
6319 *elements);
6320 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006321 }
6322
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006323 return *result;
6324}
6325
6326
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006327// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006328// one-char strings in the cache. Gives up on the first char that is
6329// not in the cache and fills the remainder with smi zeros. Returns
6330// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006331static int CopyCachedAsciiCharsToArray(Heap* heap,
6332 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006333 FixedArray* elements,
6334 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006335 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006336 FixedArray* ascii_cache = heap->single_character_string_cache();
6337 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006338 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006339 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006340 for (i = 0; i < length; ++i) {
6341 Object* value = ascii_cache->get(chars[i]);
6342 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006343 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006344 }
6345 if (i < length) {
6346 ASSERT(Smi::FromInt(0) == 0);
6347 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6348 }
6349#ifdef DEBUG
6350 for (int j = 0; j < length; ++j) {
6351 Object* element = elements->get(j);
6352 ASSERT(element == Smi::FromInt(0) ||
6353 (element->IsString() && String::cast(element)->LooksValid()));
6354 }
6355#endif
6356 return i;
6357}
6358
6359
6360// Converts a String to JSArray.
6361// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006362RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006363 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006364 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006365 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006366 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006367
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006368 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006369 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006370
6371 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006372 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006373 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006374 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006375 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006376 { MaybeObject* maybe_obj =
6377 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006378 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6379 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006380 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006381 String::FlatContent content = s->GetFlatContent();
6382 if (content.IsAscii()) {
6383 Vector<const char> chars = content.ToAsciiVector();
6384 // Note, this will initialize all elements (not only the prefix)
6385 // to prevent GC from seeing partially initialized array.
6386 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6387 chars.start(),
6388 *elements,
6389 length);
6390 } else {
6391 MemsetPointer(elements->data_start(),
6392 isolate->heap()->undefined_value(),
6393 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006394 }
6395 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006396 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006397 }
6398 for (int i = position; i < length; ++i) {
6399 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6400 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006401 }
6402
6403#ifdef DEBUG
6404 for (int i = 0; i < length; ++i) {
6405 ASSERT(String::cast(elements->get(i))->length() == 1);
6406 }
6407#endif
6408
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006409 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006410}
6411
6412
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006413RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006414 NoHandleAllocation ha;
6415 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006416 CONVERT_ARG_CHECKED(String, value, 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006417 return value->ToObject();
6418}
6419
6420
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006421bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006422 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006423 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006424 return char_length == 0;
6425}
6426
6427
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006428RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006429 NoHandleAllocation ha;
6430 ASSERT(args.length() == 1);
6431
6432 Object* number = args[0];
6433 RUNTIME_ASSERT(number->IsNumber());
6434
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006435 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006436}
6437
6438
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006439RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006440 NoHandleAllocation ha;
6441 ASSERT(args.length() == 1);
6442
6443 Object* number = args[0];
6444 RUNTIME_ASSERT(number->IsNumber());
6445
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006446 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006447}
6448
6449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006450RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006451 NoHandleAllocation ha;
6452 ASSERT(args.length() == 1);
6453
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006454 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006455
6456 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6457 if (number > 0 && number <= Smi::kMaxValue) {
6458 return Smi::FromInt(static_cast<int>(number));
6459 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006460 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006461}
6462
6463
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006464RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006465 NoHandleAllocation ha;
6466 ASSERT(args.length() == 1);
6467
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006468 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006469
6470 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6471 if (number > 0 && number <= Smi::kMaxValue) {
6472 return Smi::FromInt(static_cast<int>(number));
6473 }
6474
6475 double double_value = DoubleToInteger(number);
6476 // Map both -0 and +0 to +0.
6477 if (double_value == 0) double_value = 0;
6478
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006479 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006480}
6481
6482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006483RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006484 NoHandleAllocation ha;
6485 ASSERT(args.length() == 1);
6486
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006487 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006488 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006489}
6490
6491
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006492RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006493 NoHandleAllocation ha;
6494 ASSERT(args.length() == 1);
6495
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006496 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +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 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006502 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006503}
6504
6505
ager@chromium.org870a0b62008-11-04 11:43:05 +00006506// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6507// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006508RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006509 NoHandleAllocation ha;
6510 ASSERT(args.length() == 1);
6511
6512 Object* obj = args[0];
6513 if (obj->IsSmi()) {
6514 return obj;
6515 }
6516 if (obj->IsHeapNumber()) {
6517 double value = HeapNumber::cast(obj)->value();
6518 int int_value = FastD2I(value);
6519 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6520 return Smi::FromInt(int_value);
6521 }
6522 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006523 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006524}
6525
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006526
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006527RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006528 NoHandleAllocation ha;
6529 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006530 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006531}
6532
6533
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006534RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006535 NoHandleAllocation ha;
6536 ASSERT(args.length() == 2);
6537
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006538 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6539 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006540 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006541}
6542
6543
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006544RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006545 NoHandleAllocation ha;
6546 ASSERT(args.length() == 2);
6547
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006548 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6549 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006550 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006551}
6552
6553
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006554RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006555 NoHandleAllocation ha;
6556 ASSERT(args.length() == 2);
6557
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006558 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6559 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006560 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006561}
6562
6563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006564RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006565 NoHandleAllocation ha;
6566 ASSERT(args.length() == 1);
6567
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006568 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006569 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006570}
6571
6572
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006573RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006574 NoHandleAllocation ha;
6575 ASSERT(args.length() == 0);
6576
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006577 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006578}
6579
6580
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006581RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006582 NoHandleAllocation ha;
6583 ASSERT(args.length() == 2);
6584
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006585 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6586 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006587 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006588}
6589
6590
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006591RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006592 NoHandleAllocation ha;
6593 ASSERT(args.length() == 2);
6594
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006595 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6596 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006597
ager@chromium.org3811b432009-10-28 14:53:37 +00006598 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006599 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006600 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006601}
6602
6603
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006604RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006605 NoHandleAllocation ha;
6606 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006607 CONVERT_ARG_CHECKED(String, str1, 0);
6608 CONVERT_ARG_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006609 isolate->counters()->string_add_runtime()->Increment();
6610 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006611}
6612
6613
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006614template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006615static inline void StringBuilderConcatHelper(String* special,
6616 sinkchar* sink,
6617 FixedArray* fixed_array,
6618 int array_length) {
6619 int position = 0;
6620 for (int i = 0; i < array_length; i++) {
6621 Object* element = fixed_array->get(i);
6622 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006623 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006624 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006625 int pos;
6626 int len;
6627 if (encoded_slice > 0) {
6628 // Position and length encoded in one smi.
6629 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6630 len = StringBuilderSubstringLength::decode(encoded_slice);
6631 } else {
6632 // Position and length encoded in two smis.
6633 Object* obj = fixed_array->get(++i);
6634 ASSERT(obj->IsSmi());
6635 pos = Smi::cast(obj)->value();
6636 len = -encoded_slice;
6637 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006638 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006639 sink + position,
6640 pos,
6641 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006642 position += len;
6643 } else {
6644 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006645 int element_length = string->length();
6646 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006647 position += element_length;
6648 }
6649 }
6650}
6651
6652
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006653RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006654 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006655 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006656 CONVERT_ARG_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006657 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006658 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006659 return Failure::OutOfMemoryException();
6660 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006661 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006662 CONVERT_ARG_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006663
6664 // This assumption is used by the slice encoding in one or two smis.
6665 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6666
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006667 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006668 if (maybe_result->IsFailure()) return maybe_result;
6669
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006670 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006671 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006672 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006673 }
6674 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006675 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006676 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006677 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006678
6679 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006680 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006681 } else if (array_length == 1) {
6682 Object* first = fixed_array->get(0);
6683 if (first->IsString()) return first;
6684 }
6685
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006686 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006687 int position = 0;
6688 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006689 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006690 Object* elt = fixed_array->get(i);
6691 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006692 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006693 int smi_value = Smi::cast(elt)->value();
6694 int pos;
6695 int len;
6696 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006697 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006698 pos = StringBuilderSubstringPosition::decode(smi_value);
6699 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006700 } else {
6701 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006702 len = -smi_value;
6703 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006704 i++;
6705 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006706 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006707 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006708 Object* next_smi = fixed_array->get(i);
6709 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006710 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006711 }
6712 pos = Smi::cast(next_smi)->value();
6713 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006714 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006715 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006716 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006717 ASSERT(pos >= 0);
6718 ASSERT(len >= 0);
6719 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006720 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006721 }
6722 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006723 } else if (elt->IsString()) {
6724 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006725 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006726 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006727 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006728 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006729 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006730 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006731 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006732 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006733 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006734 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006735 return Failure::OutOfMemoryException();
6736 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006737 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006738 }
6739
6740 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006741 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006742
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006743 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006744 { MaybeObject* maybe_object =
6745 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006746 if (!maybe_object->ToObject(&object)) return maybe_object;
6747 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006748 SeqAsciiString* answer = SeqAsciiString::cast(object);
6749 StringBuilderConcatHelper(special,
6750 answer->GetChars(),
6751 fixed_array,
6752 array_length);
6753 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006754 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006755 { MaybeObject* maybe_object =
6756 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006757 if (!maybe_object->ToObject(&object)) return maybe_object;
6758 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006759 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6760 StringBuilderConcatHelper(special,
6761 answer->GetChars(),
6762 fixed_array,
6763 array_length);
6764 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006765 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006766}
6767
6768
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006769RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006770 NoHandleAllocation ha;
6771 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006772 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006773 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006774 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006775 return Failure::OutOfMemoryException();
6776 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006777 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006778 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006779
6780 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006781 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006782 }
6783 FixedArray* fixed_array = FixedArray::cast(array->elements());
6784 if (fixed_array->length() < array_length) {
6785 array_length = fixed_array->length();
6786 }
6787
6788 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006789 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006790 } else if (array_length == 1) {
6791 Object* first = fixed_array->get(0);
6792 if (first->IsString()) return first;
6793 }
6794
6795 int separator_length = separator->length();
6796 int max_nof_separators =
6797 (String::kMaxLength + separator_length - 1) / separator_length;
6798 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006799 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006800 return Failure::OutOfMemoryException();
6801 }
6802 int length = (array_length - 1) * separator_length;
6803 for (int i = 0; i < array_length; i++) {
6804 Object* element_obj = fixed_array->get(i);
6805 if (!element_obj->IsString()) {
6806 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006807 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006808 }
6809 String* element = String::cast(element_obj);
6810 int increment = element->length();
6811 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006812 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006813 return Failure::OutOfMemoryException();
6814 }
6815 length += increment;
6816 }
6817
6818 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006819 { MaybeObject* maybe_object =
6820 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006821 if (!maybe_object->ToObject(&object)) return maybe_object;
6822 }
6823 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6824
6825 uc16* sink = answer->GetChars();
6826#ifdef DEBUG
6827 uc16* end = sink + length;
6828#endif
6829
6830 String* first = String::cast(fixed_array->get(0));
6831 int first_length = first->length();
6832 String::WriteToFlat(first, sink, 0, first_length);
6833 sink += first_length;
6834
6835 for (int i = 1; i < array_length; i++) {
6836 ASSERT(sink + separator_length <= end);
6837 String::WriteToFlat(separator, sink, 0, separator_length);
6838 sink += separator_length;
6839
6840 String* element = String::cast(fixed_array->get(i));
6841 int element_length = element->length();
6842 ASSERT(sink + element_length <= end);
6843 String::WriteToFlat(element, sink, 0, element_length);
6844 sink += element_length;
6845 }
6846 ASSERT(sink == end);
6847
6848 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6849 return answer;
6850}
6851
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006852template <typename Char>
6853static void JoinSparseArrayWithSeparator(FixedArray* elements,
6854 int elements_length,
6855 uint32_t array_length,
6856 String* separator,
6857 Vector<Char> buffer) {
6858 int previous_separator_position = 0;
6859 int separator_length = separator->length();
6860 int cursor = 0;
6861 for (int i = 0; i < elements_length; i += 2) {
6862 int position = NumberToInt32(elements->get(i));
6863 String* string = String::cast(elements->get(i + 1));
6864 int string_length = string->length();
6865 if (string->length() > 0) {
6866 while (previous_separator_position < position) {
6867 String::WriteToFlat<Char>(separator, &buffer[cursor],
6868 0, separator_length);
6869 cursor += separator_length;
6870 previous_separator_position++;
6871 }
6872 String::WriteToFlat<Char>(string, &buffer[cursor],
6873 0, string_length);
6874 cursor += string->length();
6875 }
6876 }
6877 if (separator_length > 0) {
6878 // Array length must be representable as a signed 32-bit number,
6879 // otherwise the total string length would have been too large.
6880 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6881 int last_array_index = static_cast<int>(array_length - 1);
6882 while (previous_separator_position < last_array_index) {
6883 String::WriteToFlat<Char>(separator, &buffer[cursor],
6884 0, separator_length);
6885 cursor += separator_length;
6886 previous_separator_position++;
6887 }
6888 }
6889 ASSERT(cursor <= buffer.length());
6890}
6891
6892
6893RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6894 NoHandleAllocation ha;
6895 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006896 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006897 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6898 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006899 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006900 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006901 // elements_array is fast-mode JSarray of alternating positions
6902 // (increasing order) and strings.
6903 // array_length is length of original array (used to add separators);
6904 // separator is string to put between elements. Assumed to be non-empty.
6905
6906 // Find total length of join result.
6907 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006908 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006909 int max_string_length;
6910 if (is_ascii) {
6911 max_string_length = SeqAsciiString::kMaxLength;
6912 } else {
6913 max_string_length = SeqTwoByteString::kMaxLength;
6914 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006915 bool overflow = false;
6916 CONVERT_NUMBER_CHECKED(int, elements_length,
6917 Int32, elements_array->length());
6918 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6919 FixedArray* elements = FixedArray::cast(elements_array->elements());
6920 for (int i = 0; i < elements_length; i += 2) {
6921 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006922 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
6923 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006924 int length = string->length();
6925 if (is_ascii && !string->IsAsciiRepresentation()) {
6926 is_ascii = false;
6927 max_string_length = SeqTwoByteString::kMaxLength;
6928 }
6929 if (length > max_string_length ||
6930 max_string_length - length < string_length) {
6931 overflow = true;
6932 break;
6933 }
6934 string_length += length;
6935 }
6936 int separator_length = separator->length();
6937 if (!overflow && separator_length > 0) {
6938 if (array_length <= 0x7fffffffu) {
6939 int separator_count = static_cast<int>(array_length) - 1;
6940 int remaining_length = max_string_length - string_length;
6941 if ((remaining_length / separator_length) >= separator_count) {
6942 string_length += separator_length * (array_length - 1);
6943 } else {
6944 // Not room for the separators within the maximal string length.
6945 overflow = true;
6946 }
6947 } else {
6948 // Nonempty separator and at least 2^31-1 separators necessary
6949 // means that the string is too large to create.
6950 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6951 overflow = true;
6952 }
6953 }
6954 if (overflow) {
6955 // Throw OutOfMemory exception for creating too large a string.
6956 V8::FatalProcessOutOfMemory("Array join result too large.");
6957 }
6958
6959 if (is_ascii) {
6960 MaybeObject* result_allocation =
6961 isolate->heap()->AllocateRawAsciiString(string_length);
6962 if (result_allocation->IsFailure()) return result_allocation;
6963 SeqAsciiString* result_string =
6964 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6965 JoinSparseArrayWithSeparator<char>(elements,
6966 elements_length,
6967 array_length,
6968 separator,
6969 Vector<char>(result_string->GetChars(),
6970 string_length));
6971 return result_string;
6972 } else {
6973 MaybeObject* result_allocation =
6974 isolate->heap()->AllocateRawTwoByteString(string_length);
6975 if (result_allocation->IsFailure()) return result_allocation;
6976 SeqTwoByteString* result_string =
6977 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6978 JoinSparseArrayWithSeparator<uc16>(elements,
6979 elements_length,
6980 array_length,
6981 separator,
6982 Vector<uc16>(result_string->GetChars(),
6983 string_length));
6984 return result_string;
6985 }
6986}
6987
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006988
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006989RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006990 NoHandleAllocation ha;
6991 ASSERT(args.length() == 2);
6992
6993 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6994 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006995 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006996}
6997
6998
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006999RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007000 NoHandleAllocation ha;
7001 ASSERT(args.length() == 2);
7002
7003 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7004 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007005 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007006}
7007
7008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007009RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007010 NoHandleAllocation ha;
7011 ASSERT(args.length() == 2);
7012
7013 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7014 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007015 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007016}
7017
7018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007019RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007020 NoHandleAllocation ha;
7021 ASSERT(args.length() == 1);
7022
7023 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007024 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007025}
7026
7027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007028RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
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 & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007035}
7036
7037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007038RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007039 NoHandleAllocation ha;
7040 ASSERT(args.length() == 2);
7041
7042 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7043 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007044 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007045}
7046
7047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007048RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007049 NoHandleAllocation ha;
7050 ASSERT(args.length() == 2);
7051
7052 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7053 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007054 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007055}
7056
7057
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007058RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007059 NoHandleAllocation ha;
7060 ASSERT(args.length() == 2);
7061
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007062 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7063 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007064 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7065 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7066 if (x == y) return Smi::FromInt(EQUAL);
7067 Object* result;
7068 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7069 result = Smi::FromInt(EQUAL);
7070 } else {
7071 result = Smi::FromInt(NOT_EQUAL);
7072 }
7073 return result;
7074}
7075
7076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007077RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007078 NoHandleAllocation ha;
7079 ASSERT(args.length() == 2);
7080
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007081 CONVERT_ARG_CHECKED(String, x, 0);
7082 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007083
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007084 bool not_equal = !x->Equals(y);
7085 // This is slightly convoluted because the value that signifies
7086 // equality is 0 and inequality is 1 so we have to negate the result
7087 // from String::Equals.
7088 ASSERT(not_equal == 0 || not_equal == 1);
7089 STATIC_CHECK(EQUAL == 0);
7090 STATIC_CHECK(NOT_EQUAL == 1);
7091 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007092}
7093
7094
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007095RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007096 NoHandleAllocation ha;
7097 ASSERT(args.length() == 3);
7098
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007099 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7100 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007101 if (isnan(x) || isnan(y)) return args[2];
7102 if (x == y) return Smi::FromInt(EQUAL);
7103 if (isless(x, y)) return Smi::FromInt(LESS);
7104 return Smi::FromInt(GREATER);
7105}
7106
7107
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007108// Compare two Smis as if they were converted to strings and then
7109// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007110RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007111 NoHandleAllocation ha;
7112 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007113 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7114 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007115
7116 // If the integers are equal so are the string representations.
7117 if (x_value == y_value) return Smi::FromInt(EQUAL);
7118
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007119 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007120 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007121 if (x_value == 0 || y_value == 0)
7122 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007123
ager@chromium.org32912102009-01-16 10:38:43 +00007124 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007125 // smallest because the char code of '-' is less than the char code
7126 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007127
7128 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7129 // architectures using 32-bit Smis.
7130 uint32_t x_scaled = x_value;
7131 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007132 if (x_value < 0 || y_value < 0) {
7133 if (y_value >= 0) return Smi::FromInt(LESS);
7134 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007135 x_scaled = -x_value;
7136 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007137 }
7138
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007139 static const uint32_t kPowersOf10[] = {
7140 1, 10, 100, 1000, 10*1000, 100*1000,
7141 1000*1000, 10*1000*1000, 100*1000*1000,
7142 1000*1000*1000
7143 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007144
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007145 // If the integers have the same number of decimal digits they can be
7146 // compared directly as the numeric order is the same as the
7147 // lexicographic order. If one integer has fewer digits, it is scaled
7148 // by some power of 10 to have the same number of digits as the longer
7149 // integer. If the scaled integers are equal it means the shorter
7150 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007151
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007152 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7153 int x_log2 = IntegerLog2(x_scaled);
7154 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7155 x_log10 -= x_scaled < kPowersOf10[x_log10];
7156
7157 int y_log2 = IntegerLog2(y_scaled);
7158 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7159 y_log10 -= y_scaled < kPowersOf10[y_log10];
7160
7161 int tie = EQUAL;
7162
7163 if (x_log10 < y_log10) {
7164 // X has fewer digits. We would like to simply scale up X but that
7165 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7166 // be scaled up to 9_000_000_000. So we scale up by the next
7167 // smallest power and scale down Y to drop one digit. It is OK to
7168 // drop one digit from the longer integer since the final digit is
7169 // past the length of the shorter integer.
7170 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7171 y_scaled /= 10;
7172 tie = LESS;
7173 } else if (y_log10 < x_log10) {
7174 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7175 x_scaled /= 10;
7176 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007177 }
7178
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007179 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7180 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7181 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007182}
7183
7184
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007185static Object* StringInputBufferCompare(RuntimeState* state,
7186 String* x,
7187 String* y) {
7188 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7189 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007190 bufx.Reset(x);
7191 bufy.Reset(y);
7192 while (bufx.has_more() && bufy.has_more()) {
7193 int d = bufx.GetNext() - bufy.GetNext();
7194 if (d < 0) return Smi::FromInt(LESS);
7195 else if (d > 0) return Smi::FromInt(GREATER);
7196 }
7197
7198 // x is (non-trivial) prefix of y:
7199 if (bufy.has_more()) return Smi::FromInt(LESS);
7200 // y is prefix of x:
7201 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7202}
7203
7204
7205static Object* FlatStringCompare(String* x, String* y) {
7206 ASSERT(x->IsFlat());
7207 ASSERT(y->IsFlat());
7208 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7209 int prefix_length = x->length();
7210 if (y->length() < prefix_length) {
7211 prefix_length = y->length();
7212 equal_prefix_result = Smi::FromInt(GREATER);
7213 } else if (y->length() > prefix_length) {
7214 equal_prefix_result = Smi::FromInt(LESS);
7215 }
7216 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007217 String::FlatContent x_content = x->GetFlatContent();
7218 String::FlatContent y_content = y->GetFlatContent();
7219 if (x_content.IsAscii()) {
7220 Vector<const char> x_chars = x_content.ToAsciiVector();
7221 if (y_content.IsAscii()) {
7222 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007223 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007224 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007225 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007226 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7227 }
7228 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007229 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7230 if (y_content.IsAscii()) {
7231 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007232 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7233 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007234 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007235 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7236 }
7237 }
7238 Object* result;
7239 if (r == 0) {
7240 result = equal_prefix_result;
7241 } else {
7242 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7243 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007244 ASSERT(result ==
7245 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007246 return result;
7247}
7248
7249
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007250RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007251 NoHandleAllocation ha;
7252 ASSERT(args.length() == 2);
7253
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007254 CONVERT_ARG_CHECKED(String, x, 0);
7255 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007256
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007257 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007258
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007259 // A few fast case tests before we flatten.
7260 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007261 if (y->length() == 0) {
7262 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007263 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007264 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007265 return Smi::FromInt(LESS);
7266 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007267
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007268 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007269 if (d < 0) return Smi::FromInt(LESS);
7270 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007271
lrn@chromium.org303ada72010-10-27 09:33:13 +00007272 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007273 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007274 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7275 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007276 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007277 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7278 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007279
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007280 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007281 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007282}
7283
7284
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007285RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007286 NoHandleAllocation ha;
7287 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007288 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007289
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007290 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007291 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007292}
7293
7294
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007295RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007296 NoHandleAllocation ha;
7297 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007298 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007299
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007300 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007301 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007302}
7303
7304
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007305RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007306 NoHandleAllocation ha;
7307 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007308 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007309
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007310 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007311 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007312}
7313
7314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007315static const double kPiDividedBy4 = 0.78539816339744830962;
7316
7317
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007318RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007319 NoHandleAllocation ha;
7320 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007321 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007322
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007323 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7324 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007325 double result;
7326 if (isinf(x) && isinf(y)) {
7327 // Make sure that the result in case of two infinite arguments
7328 // is a multiple of Pi / 4. The sign of the result is determined
7329 // by the first argument (x) and the sign of the second argument
7330 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007331 int multiplier = (x < 0) ? -1 : 1;
7332 if (y < 0) multiplier *= 3;
7333 result = multiplier * kPiDividedBy4;
7334 } else {
7335 result = atan2(x, y);
7336 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007337 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007338}
7339
7340
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007341RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007342 NoHandleAllocation ha;
7343 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007344 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007345
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007346 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007347 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007348}
7349
7350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007351RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007352 NoHandleAllocation ha;
7353 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007354 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007355
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007356 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007357 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007358}
7359
7360
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007361RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007362 NoHandleAllocation ha;
7363 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007364 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007365
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007366 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007367 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007368}
7369
7370
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007371RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007372 NoHandleAllocation ha;
7373 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007374 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007375
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007376 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007377 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007378}
7379
7380
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007381RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007382 NoHandleAllocation ha;
7383 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007384 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007385
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007386 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007387 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007388}
7389
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007390// Slow version of Math.pow. We check for fast paths for special cases.
7391// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007392RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007393 NoHandleAllocation ha;
7394 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007395 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007396
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007397 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007398
7399 // If the second argument is a smi, it is much faster to call the
7400 // custom powi() function than the generic pow().
7401 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007402 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007403 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007404 }
7405
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007406 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007407 int y_int = static_cast<int>(y);
7408 double result;
7409 if (y == y_int) {
7410 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7411 } else if (y == 0.5) {
7412 result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0.
7413 } else if (y == -0.5) {
7414 result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0.
7415 } else {
7416 result = power_double_double(x, y);
7417 }
7418 if (isnan(result)) return isolate->heap()->nan_value();
7419 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420}
7421
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007422// 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 +00007423// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007424RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007425 NoHandleAllocation ha;
7426 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007427 isolate->counters()->math_pow()->Increment();
7428
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007429 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7430 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007431 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007432 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007433 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007434 double result = power_double_double(x, y);
7435 if (isnan(result)) return isolate->heap()->nan_value();
7436 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007437 }
7438}
7439
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007440
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007441RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007442 NoHandleAllocation ha;
7443 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007444 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007445
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007446 if (!args[0]->IsHeapNumber()) {
7447 // Must be smi. Return the argument unchanged for all the other types
7448 // to make fuzz-natives test happy.
7449 return args[0];
7450 }
7451
7452 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7453
7454 double value = number->value();
7455 int exponent = number->get_exponent();
7456 int sign = number->get_sign();
7457
danno@chromium.org160a7b02011-04-18 15:51:38 +00007458 if (exponent < -1) {
7459 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7460 if (sign) return isolate->heap()->minus_zero_value();
7461 return Smi::FromInt(0);
7462 }
7463
7464 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7465 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007466 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007467 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007468 return Smi::FromInt(static_cast<int>(value + 0.5));
7469 }
7470
7471 // If the magnitude is big enough, there's no place for fraction part. If we
7472 // try to add 0.5 to this number, 1.0 will be added instead.
7473 if (exponent >= 52) {
7474 return number;
7475 }
7476
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007477 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007478
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007479 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007480 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007481}
7482
7483
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007484RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007485 NoHandleAllocation ha;
7486 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007487 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007488
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007489 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007490 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007491}
7492
7493
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007494RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007495 NoHandleAllocation ha;
7496 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007497 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007498
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007499 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007500 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007501}
7502
7503
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007504RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007505 NoHandleAllocation ha;
7506 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007507 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007508
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007509 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007510 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007511}
7512
7513
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007514static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007515 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7516 181, 212, 243, 273, 304, 334};
7517 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7518 182, 213, 244, 274, 305, 335};
7519
7520 year += month / 12;
7521 month %= 12;
7522 if (month < 0) {
7523 year--;
7524 month += 12;
7525 }
7526
7527 ASSERT(month >= 0);
7528 ASSERT(month < 12);
7529
7530 // year_delta is an arbitrary number such that:
7531 // a) year_delta = -1 (mod 400)
7532 // b) year + year_delta > 0 for years in the range defined by
7533 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7534 // Jan 1 1970. This is required so that we don't run into integer
7535 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007536 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007537 // operations.
7538 static const int year_delta = 399999;
7539 static const int base_day = 365 * (1970 + year_delta) +
7540 (1970 + year_delta) / 4 -
7541 (1970 + year_delta) / 100 +
7542 (1970 + year_delta) / 400;
7543
7544 int year1 = year + year_delta;
7545 int day_from_year = 365 * year1 +
7546 year1 / 4 -
7547 year1 / 100 +
7548 year1 / 400 -
7549 base_day;
7550
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007551 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7552 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007553 }
7554
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007555 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007556}
7557
7558
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007559RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007560 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007561 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007562
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007563 CONVERT_SMI_ARG_CHECKED(year, 0);
7564 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007565
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007566 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007567}
7568
7569
7570static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7571static const int kDaysIn4Years = 4 * 365 + 1;
7572static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7573static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7574static const int kDays1970to2000 = 30 * 365 + 7;
7575static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7576 kDays1970to2000;
7577static const int kYearsOffset = 400000;
7578
7579static const char kDayInYear[] = {
7580 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7581 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7582 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7583 22, 23, 24, 25, 26, 27, 28,
7584 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7585 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7586 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7587 22, 23, 24, 25, 26, 27, 28, 29, 30,
7588 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7589 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7590 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7591 22, 23, 24, 25, 26, 27, 28, 29, 30,
7592 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7593 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7594 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7595 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7596 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7597 22, 23, 24, 25, 26, 27, 28, 29, 30,
7598 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7599 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7600 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7601 22, 23, 24, 25, 26, 27, 28, 29, 30,
7602 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7603 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7604
7605 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7606 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7607 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7608 22, 23, 24, 25, 26, 27, 28,
7609 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7610 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7611 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7612 22, 23, 24, 25, 26, 27, 28, 29, 30,
7613 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7614 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7615 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7616 22, 23, 24, 25, 26, 27, 28, 29, 30,
7617 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7618 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7619 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7620 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7621 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7622 22, 23, 24, 25, 26, 27, 28, 29, 30,
7623 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7624 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7625 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7626 22, 23, 24, 25, 26, 27, 28, 29, 30,
7627 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7628 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7629
7630 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7631 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7632 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7633 22, 23, 24, 25, 26, 27, 28, 29,
7634 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7635 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7636 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7637 22, 23, 24, 25, 26, 27, 28, 29, 30,
7638 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7639 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7640 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7641 22, 23, 24, 25, 26, 27, 28, 29, 30,
7642 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7643 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7644 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7645 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7646 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7647 22, 23, 24, 25, 26, 27, 28, 29, 30,
7648 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7649 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7650 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7651 22, 23, 24, 25, 26, 27, 28, 29, 30,
7652 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7653 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7654
7655 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7656 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7657 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7658 22, 23, 24, 25, 26, 27, 28,
7659 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7660 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7661 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7662 22, 23, 24, 25, 26, 27, 28, 29, 30,
7663 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7664 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7665 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7666 22, 23, 24, 25, 26, 27, 28, 29, 30,
7667 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7668 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7669 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7670 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7671 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7672 22, 23, 24, 25, 26, 27, 28, 29, 30,
7673 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7674 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7675 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7676 22, 23, 24, 25, 26, 27, 28, 29, 30,
7677 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7678 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7679
7680static const char kMonthInYear[] = {
7681 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7682 0, 0, 0, 0, 0, 0,
7683 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7684 1, 1, 1,
7685 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7686 2, 2, 2, 2, 2, 2,
7687 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7688 3, 3, 3, 3, 3,
7689 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7690 4, 4, 4, 4, 4, 4,
7691 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7692 5, 5, 5, 5, 5,
7693 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7694 6, 6, 6, 6, 6, 6,
7695 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7696 7, 7, 7, 7, 7, 7,
7697 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7698 8, 8, 8, 8, 8,
7699 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7700 9, 9, 9, 9, 9, 9,
7701 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7702 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7703 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7704 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7705
7706 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7707 0, 0, 0, 0, 0, 0,
7708 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7709 1, 1, 1,
7710 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7711 2, 2, 2, 2, 2, 2,
7712 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7713 3, 3, 3, 3, 3,
7714 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7715 4, 4, 4, 4, 4, 4,
7716 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7717 5, 5, 5, 5, 5,
7718 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7719 6, 6, 6, 6, 6, 6,
7720 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7721 7, 7, 7, 7, 7, 7,
7722 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7723 8, 8, 8, 8, 8,
7724 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7725 9, 9, 9, 9, 9, 9,
7726 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7727 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7728 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7729 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7730
7731 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7732 0, 0, 0, 0, 0, 0,
7733 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7734 1, 1, 1, 1,
7735 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7736 2, 2, 2, 2, 2, 2,
7737 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7738 3, 3, 3, 3, 3,
7739 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7740 4, 4, 4, 4, 4, 4,
7741 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7742 5, 5, 5, 5, 5,
7743 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7744 6, 6, 6, 6, 6, 6,
7745 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7746 7, 7, 7, 7, 7, 7,
7747 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7748 8, 8, 8, 8, 8,
7749 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7750 9, 9, 9, 9, 9, 9,
7751 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7752 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7753 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7754 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7755
7756 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7757 0, 0, 0, 0, 0, 0,
7758 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7759 1, 1, 1,
7760 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7761 2, 2, 2, 2, 2, 2,
7762 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7763 3, 3, 3, 3, 3,
7764 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7765 4, 4, 4, 4, 4, 4,
7766 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7767 5, 5, 5, 5, 5,
7768 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7769 6, 6, 6, 6, 6, 6,
7770 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7771 7, 7, 7, 7, 7, 7,
7772 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7773 8, 8, 8, 8, 8,
7774 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7775 9, 9, 9, 9, 9, 9,
7776 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7777 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7778 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7779 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7780
7781
7782// This function works for dates from 1970 to 2099.
7783static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007784 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007785#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007786 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007787#endif
7788
7789 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7790 date %= kDaysIn4Years;
7791
7792 month = kMonthInYear[date];
7793 day = kDayInYear[date];
7794
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007795 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007796}
7797
7798
7799static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007800 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007801#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007802 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007803#endif
7804
7805 date += kDaysOffset;
7806 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7807 date %= kDaysIn400Years;
7808
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007809 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007810
7811 date--;
7812 int yd1 = date / kDaysIn100Years;
7813 date %= kDaysIn100Years;
7814 year += 100 * yd1;
7815
7816 date++;
7817 int yd2 = date / kDaysIn4Years;
7818 date %= kDaysIn4Years;
7819 year += 4 * yd2;
7820
7821 date--;
7822 int yd3 = date / 365;
7823 date %= 365;
7824 year += yd3;
7825
7826 bool is_leap = (!yd1 || yd2) && !yd3;
7827
7828 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007829 ASSERT(is_leap || (date >= 0));
7830 ASSERT((date < 365) || (is_leap && (date < 366)));
7831 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007832 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7833 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007834
7835 if (is_leap) {
7836 day = kDayInYear[2*365 + 1 + date];
7837 month = kMonthInYear[2*365 + 1 + date];
7838 } else {
7839 day = kDayInYear[date];
7840 month = kMonthInYear[date];
7841 }
7842
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007843 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007844}
7845
7846
7847static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007848 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007849 if (date >= 0 && date < 32 * kDaysIn4Years) {
7850 DateYMDFromTimeAfter1970(date, year, month, day);
7851 } else {
7852 DateYMDFromTimeSlow(date, year, month, day);
7853 }
7854}
7855
7856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007857RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007858 NoHandleAllocation ha;
7859 ASSERT(args.length() == 2);
7860
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007861 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007862 CONVERT_ARG_CHECKED(JSArray, res_array, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007863
7864 int year, month, day;
7865 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7866
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007867 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7868 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007869 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007870
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007871 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7872 if (maybe->IsFailure()) return maybe;
7873 FixedArray* elms = FixedArray::cast(res_array->elements());
7874 elms->set(0, Smi::FromInt(year));
7875 elms->set(1, Smi::FromInt(month));
7876 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007877
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007878 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007879}
7880
7881
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007882RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007883 HandleScope scope(isolate);
7884 ASSERT(args.length() == 3);
7885
7886 Handle<JSFunction> callee = args.at<JSFunction>(0);
7887 Object** parameters = reinterpret_cast<Object**>(args[1]);
7888 const int argument_count = Smi::cast(args[2])->value();
7889
7890 Handle<JSObject> result =
7891 isolate->factory()->NewArgumentsObject(callee, argument_count);
7892 // Allocate the elements if needed.
7893 int parameter_count = callee->shared()->formal_parameter_count();
7894 if (argument_count > 0) {
7895 if (parameter_count > 0) {
7896 int mapped_count = Min(argument_count, parameter_count);
7897 Handle<FixedArray> parameter_map =
7898 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7899 parameter_map->set_map(
7900 isolate->heap()->non_strict_arguments_elements_map());
7901
7902 Handle<Map> old_map(result->map());
7903 Handle<Map> new_map =
7904 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007905 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007906
7907 result->set_map(*new_map);
7908 result->set_elements(*parameter_map);
7909
7910 // Store the context and the arguments array at the beginning of the
7911 // parameter map.
7912 Handle<Context> context(isolate->context());
7913 Handle<FixedArray> arguments =
7914 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7915 parameter_map->set(0, *context);
7916 parameter_map->set(1, *arguments);
7917
7918 // Loop over the actual parameters backwards.
7919 int index = argument_count - 1;
7920 while (index >= mapped_count) {
7921 // These go directly in the arguments array and have no
7922 // corresponding slot in the parameter map.
7923 arguments->set(index, *(parameters - index - 1));
7924 --index;
7925 }
7926
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007927 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007928 while (index >= 0) {
7929 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007930 Handle<String> name(scope_info->ParameterName(index));
7931 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007932 bool duplicate = false;
7933 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007934 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007935 duplicate = true;
7936 break;
7937 }
7938 }
7939
7940 if (duplicate) {
7941 // This goes directly in the arguments array with a hole in the
7942 // parameter map.
7943 arguments->set(index, *(parameters - index - 1));
7944 parameter_map->set_the_hole(index + 2);
7945 } else {
7946 // The context index goes in the parameter map with a hole in the
7947 // arguments array.
7948 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007949 for (int j = 0; j < context_local_count; ++j) {
7950 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007951 context_index = j;
7952 break;
7953 }
7954 }
7955 ASSERT(context_index >= 0);
7956 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007957 parameter_map->set(index + 2, Smi::FromInt(
7958 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007959 }
7960
7961 --index;
7962 }
7963 } else {
7964 // If there is no aliasing, the arguments object elements are not
7965 // special in any way.
7966 Handle<FixedArray> elements =
7967 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7968 result->set_elements(*elements);
7969 for (int i = 0; i < argument_count; ++i) {
7970 elements->set(i, *(parameters - i - 1));
7971 }
7972 }
7973 }
7974 return *result;
7975}
7976
7977
7978RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007979 NoHandleAllocation ha;
7980 ASSERT(args.length() == 3);
7981
7982 JSFunction* callee = JSFunction::cast(args[0]);
7983 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007984 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007985
lrn@chromium.org303ada72010-10-27 09:33:13 +00007986 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007987 { MaybeObject* maybe_result =
7988 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007989 if (!maybe_result->ToObject(&result)) return maybe_result;
7990 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007991 // Allocate the elements if needed.
7992 if (length > 0) {
7993 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007994 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007995 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007996 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7997 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007998
7999 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008000 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008001 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008002 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008003
8004 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008005 for (int i = 0; i < length; i++) {
8006 array->set(i, *--parameters, mode);
8007 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008008 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008009 }
8010 return result;
8011}
8012
8013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008014RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008015 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008016 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008017 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8018 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
8019 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008020
whesse@chromium.org7b260152011-06-20 15:33:18 +00008021 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008022 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008023 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008024 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008025 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8026 context,
8027 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008028 return *result;
8029}
8030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008031
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008032// Find the arguments of the JavaScript function invocation that called
8033// into C++ code. Collect these in a newly allocated array of handles (possibly
8034// prefixed by a number of empty handles).
8035static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8036 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008037 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008038 // Find frame containing arguments passed to the caller.
8039 JavaScriptFrameIterator it;
8040 JavaScriptFrame* frame = it.frame();
8041 List<JSFunction*> functions(2);
8042 frame->GetFunctions(&functions);
8043 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008044 int inlined_jsframe_index = functions.length() - 1;
8045 JSFunction* inlined_function = functions[inlined_jsframe_index];
8046 Vector<SlotRef> args_slots =
8047 SlotRef::ComputeSlotMappingForArguments(
8048 frame,
8049 inlined_jsframe_index,
8050 inlined_function->shared()->formal_parameter_count());
8051
8052 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008053
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008054 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008055 SmartArrayPointer<Handle<Object> > param_data(
8056 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008057 for (int i = 0; i < args_count; i++) {
8058 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008059 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008060 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008061
8062 args_slots.Dispose();
8063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008064 return param_data;
8065 } else {
8066 it.AdvanceToArgumentsFrame();
8067 frame = it.frame();
8068 int args_count = frame->ComputeParametersCount();
8069
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008070 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008071 SmartArrayPointer<Handle<Object> > param_data(
8072 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008073 for (int i = 0; i < args_count; i++) {
8074 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008075 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008076 }
8077 return param_data;
8078 }
8079}
8080
8081
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008082RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8083 HandleScope scope(isolate);
8084 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008085 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008086 RUNTIME_ASSERT(args[3]->IsNumber());
8087 Handle<Object> bindee = args.at<Object>(1);
8088
8089 // TODO(lrn): Create bound function in C++ code from premade shared info.
8090 bound_function->shared()->set_bound(true);
8091 // Get all arguments of calling function (Function.prototype.bind).
8092 int argc = 0;
8093 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8094 // Don't count the this-arg.
8095 if (argc > 0) {
8096 ASSERT(*arguments[0] == args[2]);
8097 argc--;
8098 } else {
8099 ASSERT(args[2]->IsUndefined());
8100 }
8101 // Initialize array of bindings (function, this, and any existing arguments
8102 // if the function was already bound).
8103 Handle<FixedArray> new_bindings;
8104 int i;
8105 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8106 Handle<FixedArray> old_bindings(
8107 JSFunction::cast(*bindee)->function_bindings());
8108 new_bindings =
8109 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8110 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8111 i = 0;
8112 for (int n = old_bindings->length(); i < n; i++) {
8113 new_bindings->set(i, old_bindings->get(i));
8114 }
8115 } else {
8116 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8117 new_bindings = isolate->factory()->NewFixedArray(array_size);
8118 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8119 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8120 i = 2;
8121 }
8122 // Copy arguments, skipping the first which is "this_arg".
8123 for (int j = 0; j < argc; j++, i++) {
8124 new_bindings->set(i, *arguments[j + 1]);
8125 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008126 new_bindings->set_map_no_write_barrier(
8127 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008128 bound_function->set_function_bindings(*new_bindings);
8129
8130 // Update length.
8131 Handle<String> length_symbol = isolate->factory()->length_symbol();
8132 Handle<Object> new_length(args.at<Object>(3));
8133 PropertyAttributes attr =
8134 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8135 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8136 return *bound_function;
8137}
8138
8139
8140RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8141 HandleScope handles(isolate);
8142 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008143 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008144 if (callable->IsJSFunction()) {
8145 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8146 if (function->shared()->bound()) {
8147 Handle<FixedArray> bindings(function->function_bindings());
8148 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8149 return *isolate->factory()->NewJSArrayWithElements(bindings);
8150 }
8151 }
8152 return isolate->heap()->undefined_value();
8153}
8154
8155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008156RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008157 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008158 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008159 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008160 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008161 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008162
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008163 // The argument is a bound function. Extract its bound arguments
8164 // and callable.
8165 Handle<FixedArray> bound_args =
8166 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8167 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8168 Handle<Object> bound_function(
8169 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8170 ASSERT(!bound_function->IsJSFunction() ||
8171 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008172
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008173 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008174 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008175 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008176 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008177 param_data[i] = Handle<Object>(bound_args->get(
8178 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008179 }
8180
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008181 if (!bound_function->IsJSFunction()) {
8182 bool exception_thrown;
8183 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8184 &exception_thrown);
8185 if (exception_thrown) return Failure::Exception();
8186 }
8187 ASSERT(bound_function->IsJSFunction());
8188
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008189 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008190 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008191 Execution::New(Handle<JSFunction>::cast(bound_function),
8192 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008193 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008194 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008195 }
8196 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008197 return *result;
8198}
8199
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008200
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008201static void TrySettingInlineConstructStub(Isolate* isolate,
8202 Handle<JSFunction> function) {
8203 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008204 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008205 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008206 }
8207 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008208 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008209 Handle<Code> code = compiler.CompileConstructStub(function);
8210 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008211 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008212}
8213
8214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008215RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008216 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008217 ASSERT(args.length() == 1);
8218
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008219 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008220
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008221 // If the constructor isn't a proper function we throw a type error.
8222 if (!constructor->IsJSFunction()) {
8223 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8224 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008225 isolate->factory()->NewTypeError("not_constructor", arguments);
8226 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008227 }
8228
8229 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008230
8231 // If function should not have prototype, construction is not allowed. In this
8232 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008233 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008234 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8235 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008236 isolate->factory()->NewTypeError("not_constructor", arguments);
8237 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008238 }
8239
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008240#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008241 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008242 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008243 if (debug->StepInActive()) {
8244 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008245 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008246#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008247
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008248 if (function->has_initial_map()) {
8249 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008250 // The 'Function' function ignores the receiver object when
8251 // called using 'new' and creates a new JSFunction object that
8252 // is returned. The receiver object is only used for error
8253 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008254 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008255 // allocate JSFunctions since it does not properly initialize
8256 // the shared part of the function. Since the receiver is
8257 // ignored anyway, we use the global object as the receiver
8258 // instead of a new JSFunction object. This way, errors are
8259 // reported the same way whether or not 'Function' is called
8260 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008261 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008262 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008263 }
8264
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008265 // The function should be compiled for the optimization hints to be
8266 // available. We cannot use EnsureCompiled because that forces a
8267 // compilation through the shared function info which makes it
8268 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008269 if (!function->is_compiled()) {
8270 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8271 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008272
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008273 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008274 if (!function->has_initial_map() &&
8275 shared->IsInobjectSlackTrackingInProgress()) {
8276 // The tracking is already in progress for another function. We can only
8277 // track one initial_map at a time, so we force the completion before the
8278 // function is called as a constructor for the first time.
8279 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008280 }
8281
8282 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008283 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8284 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008285 // Delay setting the stub if inobject slack tracking is in progress.
8286 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008287 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008288 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008289
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008290 isolate->counters()->constructed_objects()->Increment();
8291 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008292
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008293 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008294}
8295
8296
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008297RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008298 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008299 ASSERT(args.length() == 1);
8300
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008301 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008302 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008303 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008304
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008305 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008306}
8307
8308
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008309RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008310 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008311 ASSERT(args.length() == 1);
8312
8313 Handle<JSFunction> function = args.at<JSFunction>(0);
8314#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008315 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008316 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008317 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008318 PrintF("]\n");
8319 }
8320#endif
8321
lrn@chromium.org34e60782011-09-15 07:25:40 +00008322 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008323 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008324 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008325 return Failure::Exception();
8326 }
8327
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008328 // All done. Return the compiled code.
8329 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008330 return function->code();
8331}
8332
8333
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008334RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008335 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008336 ASSERT(args.length() == 1);
8337 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008338
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00008339 function->shared()->set_profiler_ticks(0);
8340
lrn@chromium.org34e60782011-09-15 07:25:40 +00008341 // If the function is not compiled ignore the lazy
8342 // recompilation. This can happen if the debugger is activated and
8343 // the function is returned to the not compiled state.
8344 if (!function->shared()->is_compiled()) {
8345 function->ReplaceCode(function->shared()->code());
8346 return function->code();
8347 }
8348
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008349 // If the function is not optimizable or debugger is active continue using the
8350 // code from the full compiler.
8351 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008352 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008353 if (FLAG_trace_opt) {
8354 PrintF("[failed to optimize ");
8355 function->PrintName();
8356 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8357 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008358 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008359 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008360 function->ReplaceCode(function->shared()->code());
8361 return function->code();
8362 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008363 if (JSFunction::CompileOptimized(function,
8364 AstNode::kNoNumber,
8365 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008366 return function->code();
8367 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008368 if (FLAG_trace_opt) {
8369 PrintF("[failed to optimize ");
8370 function->PrintName();
8371 PrintF(": optimized compilation failed]\n");
8372 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008373 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008374 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008375}
8376
8377
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008378class ActivationsFinder : public ThreadVisitor {
8379 public:
8380 explicit ActivationsFinder(JSFunction* function)
8381 : function_(function), has_activations_(false) {}
8382
8383 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8384 if (has_activations_) return;
8385
8386 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8387 JavaScriptFrame* frame = it.frame();
8388 if (frame->is_optimized() && frame->function() == function_) {
8389 has_activations_ = true;
8390 return;
8391 }
8392 }
8393 }
8394
8395 bool has_activations() { return has_activations_; }
8396
8397 private:
8398 JSFunction* function_;
8399 bool has_activations_;
8400};
8401
8402
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008403RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008404 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008405 ASSERT(args.length() == 1);
8406 RUNTIME_ASSERT(args[0]->IsSmi());
8407 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008408 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008409 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8410 ASSERT(isolate->heap()->IsAllocationAllowed());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008411 int jsframes = deoptimizer->jsframe_count();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008412
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008413 deoptimizer->MaterializeHeapNumbers();
8414 delete deoptimizer;
8415
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008416 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008417 JavaScriptFrame* frame = NULL;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008418 for (int i = 0; i < jsframes - 1; i++) it.Advance();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008419 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008420
8421 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008422 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008423 Handle<Object> arguments;
8424 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008425 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008426 if (arguments.is_null()) {
8427 // FunctionGetArguments can't throw an exception, so cast away the
8428 // doubt with an assert.
8429 arguments = Handle<Object>(
8430 Accessors::FunctionGetArguments(*function,
8431 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008432 ASSERT(*arguments != isolate->heap()->null_value());
8433 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008434 }
8435 frame->SetExpression(i, *arguments);
8436 }
8437 }
8438
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008439 if (type == Deoptimizer::EAGER) {
8440 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008441 }
8442
8443 // Avoid doing too much work when running with --always-opt and keep
8444 // the optimized code around.
8445 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008446 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008447 }
8448
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008449 // Find other optimized activations of the function.
8450 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008451 while (!it.done()) {
8452 JavaScriptFrame* frame = it.frame();
8453 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008454 has_other_activations = true;
8455 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008456 }
8457 it.Advance();
8458 }
8459
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008460 if (!has_other_activations) {
8461 ActivationsFinder activations_finder(*function);
8462 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8463 has_other_activations = activations_finder.has_activations();
8464 }
8465
8466 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008467 if (FLAG_trace_deopt) {
8468 PrintF("[removing optimized code for: ");
8469 function->PrintName();
8470 PrintF("]\n");
8471 }
8472 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008473 } else {
8474 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008475 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008476 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008477}
8478
8479
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008480RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008481 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008482 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008483 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008484}
8485
8486
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008487RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008488 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008489 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008490 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008491 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008492
8493 Deoptimizer::DeoptimizeFunction(*function);
8494
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008495 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008496}
8497
8498
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008499RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8500#if defined(USE_SIMULATOR)
8501 return isolate->heap()->true_value();
8502#else
8503 return isolate->heap()->false_value();
8504#endif
8505}
8506
8507
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008508RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8509 HandleScope scope(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008510 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008511 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008512
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008513 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8514 function->MarkForLazyRecompilation();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008515
8516 Code* unoptimized = function->shared()->code();
8517 if (args.length() == 2 &&
8518 unoptimized->kind() == Code::FUNCTION) {
8519 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8520 CHECK(type->IsEqualTo(CStrVector("osr")));
8521 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8522 unoptimized->set_allow_osr_at_loop_nesting_level(
8523 Code::kMaxLoopNestingMarker);
8524 }
8525
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008526 return isolate->heap()->undefined_value();
8527}
8528
8529
lrn@chromium.org1c092762011-05-09 09:42:16 +00008530RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8531 HandleScope scope(isolate);
8532 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008533 // The least significant bit (after untagging) indicates whether the
8534 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008535 if (!V8::UseCrankshaft()) {
8536 return Smi::FromInt(4); // 4 == "never".
8537 }
8538 if (FLAG_always_opt) {
8539 return Smi::FromInt(3); // 3 == "always".
8540 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008541 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008542 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8543 : Smi::FromInt(2); // 2 == "no".
8544}
8545
8546
8547RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8548 HandleScope scope(isolate);
8549 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008550 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008551 return Smi::FromInt(function->shared()->opt_count());
8552}
8553
8554
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008555RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008556 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008557 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008558 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008559
8560 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008561 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008562
8563 // We have hit a back edge in an unoptimized frame for a function that was
8564 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008565 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008566 // Keep track of whether we've succeeded in optimizing.
8567 bool succeeded = unoptimized->optimizable();
8568 if (succeeded) {
8569 // If we are trying to do OSR when there are already optimized
8570 // activations of the function, it means (a) the function is directly or
8571 // indirectly recursive and (b) an optimized invocation has been
8572 // deoptimized so that we are currently in an unoptimized activation.
8573 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008574 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008575 while (succeeded && !it.done()) {
8576 JavaScriptFrame* frame = it.frame();
8577 succeeded = !frame->is_optimized() || frame->function() != *function;
8578 it.Advance();
8579 }
8580 }
8581
8582 int ast_id = AstNode::kNoNumber;
8583 if (succeeded) {
8584 // The top JS function is this one, the PC is somewhere in the
8585 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008586 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008587 JavaScriptFrame* frame = it.frame();
8588 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008589 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008590 ASSERT(unoptimized->contains(frame->pc()));
8591
8592 // Use linear search of the unoptimized code's stack check table to find
8593 // the AST id matching the PC.
8594 Address start = unoptimized->instruction_start();
8595 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008596 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008597 uint32_t table_length = Memory::uint32_at(table_cursor);
8598 table_cursor += kIntSize;
8599 for (unsigned i = 0; i < table_length; ++i) {
8600 // Table entries are (AST id, pc offset) pairs.
8601 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8602 if (pc_offset == target_pc_offset) {
8603 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8604 break;
8605 }
8606 table_cursor += 2 * kIntSize;
8607 }
8608 ASSERT(ast_id != AstNode::kNoNumber);
8609 if (FLAG_trace_osr) {
8610 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8611 function->PrintName();
8612 PrintF("]\n");
8613 }
8614
8615 // Try to compile the optimized code. A true return value from
8616 // CompileOptimized means that compilation succeeded, not necessarily
8617 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008618 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008619 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008620 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8621 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008622 if (data->OsrPcOffset()->value() >= 0) {
8623 if (FLAG_trace_osr) {
8624 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008625 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008626 }
8627 ASSERT(data->OsrAstId()->value() == ast_id);
8628 } else {
8629 // We may never generate the desired OSR entry if we emit an
8630 // early deoptimize.
8631 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008632 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008633 } else {
8634 succeeded = false;
8635 }
8636 }
8637
8638 // Revert to the original stack checks in the original unoptimized code.
8639 if (FLAG_trace_osr) {
8640 PrintF("[restoring original stack checks in ");
8641 function->PrintName();
8642 PrintF("]\n");
8643 }
yangguo@chromium.org56454712012-02-16 15:33:53 +00008644 Handle<Code> check_code;
8645#ifdef V8_TARGET_ARCH_IA32
8646 if (FLAG_count_based_interrupts) {
8647 InterruptStub interrupt_stub;
8648 check_code = interrupt_stub.GetCode();
8649 } else // NOLINT
8650#endif
8651 { // NOLINT
8652 StackCheckStub check_stub;
8653 check_code = check_stub.GetCode();
8654 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008655 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008656 Deoptimizer::RevertStackCheckCode(*unoptimized,
8657 *check_code,
8658 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008659
8660 // Allow OSR only at nesting level zero again.
8661 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8662
8663 // If the optimization attempt succeeded, return the AST id tagged as a
8664 // smi. This tells the builtin that we need to translate the unoptimized
8665 // frame to an optimized one.
8666 if (succeeded) {
8667 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8668 return Smi::FromInt(ast_id);
8669 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008670 if (function->IsMarkedForLazyRecompilation()) {
8671 function->ReplaceCode(function->shared()->code());
8672 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008673 return Smi::FromInt(-1);
8674 }
8675}
8676
8677
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008678RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8679 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8680 return isolate->heap()->undefined_value();
8681}
8682
8683
danno@chromium.orgc612e022011-11-10 11:38:15 +00008684RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8685 HandleScope scope(isolate);
8686 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008687 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008688 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8689 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008690
8691 // If there are too many arguments, allocate argv via malloc.
8692 const int argv_small_size = 10;
8693 Handle<Object> argv_small_buffer[argv_small_size];
8694 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8695 Handle<Object>* argv = argv_small_buffer;
8696 if (argc > argv_small_size) {
8697 argv = new Handle<Object>[argc];
8698 if (argv == NULL) return isolate->StackOverflow();
8699 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8700 }
8701
8702 for (int i = 0; i < argc; ++i) {
8703 MaybeObject* maybe = args[1 + i];
8704 Object* object;
8705 if (!maybe->To<Object>(&object)) return maybe;
8706 argv[i] = Handle<Object>(object);
8707 }
8708
8709 bool threw;
8710 Handle<JSReceiver> hfun(fun);
8711 Handle<Object> hreceiver(receiver);
8712 Handle<Object> result =
8713 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8714
8715 if (threw) return Failure::Exception();
8716 return *result;
8717}
8718
8719
lrn@chromium.org34e60782011-09-15 07:25:40 +00008720RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8721 HandleScope scope(isolate);
8722 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008723 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008724 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008725 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008726 CONVERT_SMI_ARG_CHECKED(offset, 3);
8727 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008728 ASSERT(offset >= 0);
8729 ASSERT(argc >= 0);
8730
8731 // If there are too many arguments, allocate argv via malloc.
8732 const int argv_small_size = 10;
8733 Handle<Object> argv_small_buffer[argv_small_size];
8734 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8735 Handle<Object>* argv = argv_small_buffer;
8736 if (argc > argv_small_size) {
8737 argv = new Handle<Object>[argc];
8738 if (argv == NULL) return isolate->StackOverflow();
8739 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8740 }
8741
8742 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008743 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008744 }
8745
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008746 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008747 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008748 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008749
8750 if (threw) return Failure::Exception();
8751 return *result;
8752}
8753
8754
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008755RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008756 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008757 ASSERT(args.length() == 1);
8758 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8759 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8760}
8761
8762
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008763RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008764 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008765 ASSERT(args.length() == 1);
8766 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8767 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8768}
8769
8770
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008771RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008772 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008773 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008774
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008775 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008776 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008777 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008778 { MaybeObject* maybe_result =
8779 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008780 if (!maybe_result->ToObject(&result)) return maybe_result;
8781 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008782
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008783 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008784
kasper.lund7276f142008-07-30 08:49:36 +00008785 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008786}
8787
lrn@chromium.org303ada72010-10-27 09:33:13 +00008788
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008789RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8790 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008791 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008792 JSObject* extension_object;
8793 if (args[0]->IsJSObject()) {
8794 extension_object = JSObject::cast(args[0]);
8795 } else {
8796 // Convert the object to a proper JavaScript object.
8797 MaybeObject* maybe_js_object = args[0]->ToObject();
8798 if (!maybe_js_object->To(&extension_object)) {
8799 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8800 HandleScope scope(isolate);
8801 Handle<Object> handle = args.at<Object>(0);
8802 Handle<Object> result =
8803 isolate->factory()->NewTypeError("with_expression",
8804 HandleVector(&handle, 1));
8805 return isolate->Throw(*result);
8806 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008807 return maybe_js_object;
8808 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008809 }
8810 }
8811
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008812 JSFunction* function;
8813 if (args[1]->IsSmi()) {
8814 // A smi sentinel indicates a context nested inside global code rather
8815 // than some function. There is a canonical empty function that can be
8816 // gotten from the global context.
8817 function = isolate->context()->global_context()->closure();
8818 } else {
8819 function = JSFunction::cast(args[1]);
8820 }
8821
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008822 Context* context;
8823 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008824 isolate->heap()->AllocateWithContext(function,
8825 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008826 extension_object);
8827 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008828 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008829 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008830}
8831
8832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008833RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008834 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008835 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008836 String* name = String::cast(args[0]);
8837 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008838 JSFunction* function;
8839 if (args[2]->IsSmi()) {
8840 // A smi sentinel indicates a context nested inside global code rather
8841 // than some function. There is a canonical empty function that can be
8842 // gotten from the global context.
8843 function = isolate->context()->global_context()->closure();
8844 } else {
8845 function = JSFunction::cast(args[2]);
8846 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008847 Context* context;
8848 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008849 isolate->heap()->AllocateCatchContext(function,
8850 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008851 name,
8852 thrown_object);
8853 if (!maybe_context->To(&context)) return maybe_context;
8854 isolate->set_context(context);
8855 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008856}
8857
8858
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008859RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8860 NoHandleAllocation ha;
8861 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008862 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008863 JSFunction* function;
8864 if (args[1]->IsSmi()) {
8865 // A smi sentinel indicates a context nested inside global code rather
8866 // than some function. There is a canonical empty function that can be
8867 // gotten from the global context.
8868 function = isolate->context()->global_context()->closure();
8869 } else {
8870 function = JSFunction::cast(args[1]);
8871 }
8872 Context* context;
8873 MaybeObject* maybe_context =
8874 isolate->heap()->AllocateBlockContext(function,
8875 isolate->context(),
8876 scope_info);
8877 if (!maybe_context->To(&context)) return maybe_context;
8878 isolate->set_context(context);
8879 return context;
8880}
8881
8882
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008883RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008884 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008885 ASSERT(args.length() == 2);
8886
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008887 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8888 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008889
8890 int index;
8891 PropertyAttributes attributes;
8892 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008893 BindingFlags binding_flags;
8894 Handle<Object> holder = context->Lookup(name,
8895 flags,
8896 &index,
8897 &attributes,
8898 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008899
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008900 // If the slot was not found the result is true.
8901 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008902 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008903 }
8904
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008905 // If the slot was found in a context, it should be DONT_DELETE.
8906 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008907 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008908 }
8909
8910 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008911 // the global object, or the subject of a with. Try to delete it
8912 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008913 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008914 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008915}
8916
8917
ager@chromium.orga1645e22009-09-09 19:27:10 +00008918// A mechanism to return a pair of Object pointers in registers (if possible).
8919// How this is achieved is calling convention-dependent.
8920// All currently supported x86 compiles uses calling conventions that are cdecl
8921// variants where a 64-bit value is returned in two 32-bit registers
8922// (edx:eax on ia32, r1:r0 on ARM).
8923// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8924// In Win64 calling convention, a struct of two pointers is returned in memory,
8925// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008926#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008927struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008928 MaybeObject* x;
8929 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008930};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008931
lrn@chromium.org303ada72010-10-27 09:33:13 +00008932static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008933 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008934 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8935 // In Win64 they are assigned to a hidden first argument.
8936 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008937}
8938#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008939typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008940static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008941 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008942 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008943}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008944#endif
8945
8946
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008947static inline MaybeObject* Unhole(Heap* heap,
8948 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008949 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008950 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8951 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008952 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008953}
8954
8955
danno@chromium.org40cb8782011-05-25 07:58:50 +00008956static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8957 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008958 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008959 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008960 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008961 JSFunction* context_extension_function =
8962 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008963 // If the holder isn't a context extension object, we just return it
8964 // as the receiver. This allows arguments objects to be used as
8965 // receivers, but only if they are put in the context scope chain
8966 // explicitly via a with-statement.
8967 Object* constructor = holder->map()->constructor();
8968 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008969 // Fall back to using the global object as the implicit receiver if
8970 // the property turns out to be a local variable allocated in a
8971 // context extension object - introduced via eval. Implicit global
8972 // receivers are indicated with the hole value.
8973 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008974}
8975
8976
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008977static ObjectPair LoadContextSlotHelper(Arguments args,
8978 Isolate* isolate,
8979 bool throw_error) {
8980 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008981 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008982
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008983 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008984 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008985 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008986 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008987 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008988
8989 int index;
8990 PropertyAttributes attributes;
8991 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008992 BindingFlags binding_flags;
8993 Handle<Object> holder = context->Lookup(name,
8994 flags,
8995 &index,
8996 &attributes,
8997 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008998
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008999 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009000 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009001 ASSERT(holder->IsContext());
9002 // If the "property" we were looking for is a local variable, the
9003 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00009004 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009005 // Use the hole as the receiver to signal that the receiver is implicit
9006 // and that the global receiver should be used (as distinguished from an
9007 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00009008 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009009 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009010 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009011 switch (binding_flags) {
9012 case MUTABLE_CHECK_INITIALIZED:
9013 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9014 if (value->IsTheHole()) {
9015 Handle<Object> reference_error =
9016 isolate->factory()->NewReferenceError("not_defined",
9017 HandleVector(&name, 1));
9018 return MakePair(isolate->Throw(*reference_error), NULL);
9019 }
9020 // FALLTHROUGH
9021 case MUTABLE_IS_INITIALIZED:
9022 case IMMUTABLE_IS_INITIALIZED:
9023 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9024 ASSERT(!value->IsTheHole());
9025 return MakePair(value, *receiver);
9026 case IMMUTABLE_CHECK_INITIALIZED:
9027 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9028 case MISSING_BINDING:
9029 UNREACHABLE();
9030 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009031 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009032 }
9033
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009034 // Otherwise, if the slot was found the holder is a context extension
9035 // object, subject of a with, or a global object. We read the named
9036 // property from it.
9037 if (!holder.is_null()) {
9038 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9039 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009040 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009041 Handle<Object> receiver_handle(object->IsGlobalObject()
9042 ? GlobalObject::cast(*object)->global_receiver()
9043 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009044
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009045 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009046 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009047 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009048 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009049 }
9050
9051 if (throw_error) {
9052 // The property doesn't exist - throw exception.
9053 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009054 isolate->factory()->NewReferenceError("not_defined",
9055 HandleVector(&name, 1));
9056 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009057 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009058 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009059 return MakePair(isolate->heap()->undefined_value(),
9060 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009061 }
9062}
9063
9064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009065RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009066 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009067}
9068
9069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009070RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009071 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009072}
9073
9074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009075RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009076 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009077 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009078
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009079 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009080 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
9081 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009082 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9083 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9084 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009085
9086 int index;
9087 PropertyAttributes attributes;
9088 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009089 BindingFlags binding_flags;
9090 Handle<Object> holder = context->Lookup(name,
9091 flags,
9092 &index,
9093 &attributes,
9094 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009095
9096 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009097 // The property was found in a context slot.
9098 Handle<Context> context = Handle<Context>::cast(holder);
9099 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9100 context->get(index)->IsTheHole()) {
9101 Handle<Object> error =
9102 isolate->factory()->NewReferenceError("not_defined",
9103 HandleVector(&name, 1));
9104 return isolate->Throw(*error);
9105 }
9106 // Ignore if read_only variable.
9107 if ((attributes & READ_ONLY) == 0) {
9108 // Context is a fixed array and set cannot fail.
9109 context->set(index, *value);
9110 } else if (strict_mode == kStrictMode) {
9111 // Setting read only property in strict mode.
9112 Handle<Object> error =
9113 isolate->factory()->NewTypeError("strict_cannot_assign",
9114 HandleVector(&name, 1));
9115 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009116 }
9117 return *value;
9118 }
9119
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009120 // Slow case: The property is not in a context slot. It is either in a
9121 // context extension object, a property of the subject of a with, or a
9122 // property of the global object.
9123 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009124
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009125 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009126 // The property exists on the holder.
9127 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009128 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009129 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009130 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009131
9132 if (strict_mode == kStrictMode) {
9133 // Throw in strict mode (assignment to undefined variable).
9134 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009135 isolate->factory()->NewReferenceError(
9136 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009137 return isolate->Throw(*error);
9138 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009139 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009140 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009141 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009142 }
9143
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009144 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009145 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009146 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009147 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009148 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009149 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009150 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009151 // Setting read only property in strict mode.
9152 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009153 isolate->factory()->NewTypeError(
9154 "strict_cannot_assign", HandleVector(&name, 1));
9155 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009156 }
9157 return *value;
9158}
9159
9160
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009161RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009162 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009163 ASSERT(args.length() == 1);
9164
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009165 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009166}
9167
9168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009169RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009170 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009171 ASSERT(args.length() == 1);
9172
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009173 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009174}
9175
9176
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009177RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009178 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009179 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009180}
9181
9182
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009183RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009184 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009185 ASSERT(args.length() == 1);
9186
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009187 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009188 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009189 isolate->factory()->NewReferenceError("not_defined",
9190 HandleVector(&name, 1));
9191 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009192}
9193
9194
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009195RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009196 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009197
9198 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009199 if (isolate->stack_guard()->IsStackOverflow()) {
9200 NoHandleAllocation na;
9201 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009202 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009203
ulan@chromium.org812308e2012-02-29 15:58:45 +00009204 return Execution::HandleStackGuardInterrupt(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009205}
9206
9207
yangguo@chromium.org56454712012-02-16 15:33:53 +00009208RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
9209 ASSERT(args.length() == 0);
ulan@chromium.org812308e2012-02-29 15:58:45 +00009210 return Execution::HandleStackGuardInterrupt(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00009211}
9212
9213
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009214static int StackSize() {
9215 int n = 0;
9216 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9217 return n;
9218}
9219
9220
9221static void PrintTransition(Object* result) {
9222 // indentation
9223 { const int nmax = 80;
9224 int n = StackSize();
9225 if (n <= nmax)
9226 PrintF("%4d:%*s", n, n, "");
9227 else
9228 PrintF("%4d:%*s", n, nmax, "...");
9229 }
9230
9231 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009232 JavaScriptFrame::PrintTop(stdout, true, false);
9233 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009234 } else {
9235 // function result
9236 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009237 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009238 PrintF("\n");
9239 }
9240}
9241
9242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009243RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009244 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009245 NoHandleAllocation ha;
9246 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009247 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009248}
9249
9250
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009251RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009252 NoHandleAllocation ha;
9253 PrintTransition(args[0]);
9254 return args[0]; // return TOS
9255}
9256
9257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009258RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009259 NoHandleAllocation ha;
9260 ASSERT(args.length() == 1);
9261
9262#ifdef DEBUG
9263 if (args[0]->IsString()) {
9264 // If we have a string, assume it's a code "marker"
9265 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009266 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009267 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009268 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9269 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009270 } else {
9271 PrintF("DebugPrint: ");
9272 }
9273 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009274 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009275 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009276 HeapObject::cast(args[0])->map()->Print();
9277 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009278#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009279 // ShortPrint is available in release mode. Print is not.
9280 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009281#endif
9282 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009283 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009284
9285 return args[0]; // return TOS
9286}
9287
9288
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009289RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009290 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009291 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009292 isolate->PrintStack();
9293 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009294}
9295
9296
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009297RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009298 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009299 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009300
9301 // According to ECMA-262, section 15.9.1, page 117, the precision of
9302 // the number in a Date object representing a particular instant in
9303 // time is milliseconds. Therefore, we floor the result of getting
9304 // the OS time.
9305 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009306 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009307}
9308
9309
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009310RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009311 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009312 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009313
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009314 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009315 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009316
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009317 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009318
9319 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009320 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009321 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009322 RUNTIME_ASSERT(output->HasFastElements());
9323
9324 AssertNoAllocation no_allocation;
9325
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009326 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009327 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9328 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009329 String::FlatContent str_content = str->GetFlatContent();
9330 if (str_content.IsAscii()) {
9331 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009332 output_array,
9333 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009334 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009335 ASSERT(str_content.IsTwoByte());
9336 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009337 output_array,
9338 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009339 }
9340
9341 if (result) {
9342 return *output;
9343 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009344 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009345 }
9346}
9347
9348
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009349RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009350 NoHandleAllocation ha;
9351 ASSERT(args.length() == 1);
9352
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009353 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009354 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009355 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009356}
9357
9358
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009359RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009360 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009361 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009362
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009363 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009364}
9365
9366
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009367RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009368 NoHandleAllocation ha;
9369 ASSERT(args.length() == 1);
9370
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009371 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009372 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009373}
9374
9375
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009376RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009377 ASSERT(args.length() == 1);
9378 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009379 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009380 return JSGlobalObject::cast(global)->global_receiver();
9381}
9382
9383
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009384RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009385 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009386 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009387 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009388
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009389 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009390 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009391 Handle<Object> result;
9392 if (source->IsSeqAsciiString()) {
9393 result = JsonParser<true>::Parse(source);
9394 } else {
9395 result = JsonParser<false>::Parse(source);
9396 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009397 if (result.is_null()) {
9398 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009399 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009400 return Failure::Exception();
9401 }
9402 return *result;
9403}
9404
9405
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009406bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9407 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009408 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9409 // Check with callback if set.
9410 AllowCodeGenerationFromStringsCallback callback =
9411 isolate->allow_code_gen_callback();
9412 if (callback == NULL) {
9413 // No callback set and code generation disallowed.
9414 return false;
9415 } else {
9416 // Callback set. Let it decide if code generation is allowed.
9417 VMState state(isolate, EXTERNAL);
9418 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009419 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009420}
9421
9422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009423RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009424 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009425 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009426 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009427
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009428 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009429 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009430
9431 // Check if global context allows code generation from
9432 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009433 if (context->allow_code_gen_from_strings()->IsFalse() &&
9434 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009435 return isolate->Throw(*isolate->factory()->NewError(
9436 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9437 }
9438
9439 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009440 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009441 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009442 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009443 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009444 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9445 context,
9446 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009447 return *fun;
9448}
9449
9450
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009451static ObjectPair CompileGlobalEval(Isolate* isolate,
9452 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009453 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009454 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009455 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009456 Handle<Context> context = Handle<Context>(isolate->context());
9457 Handle<Context> global_context = Handle<Context>(context->global_context());
9458
9459 // Check if global context allows code generation from
9460 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009461 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9462 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009463 isolate->Throw(*isolate->factory()->NewError(
9464 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9465 return MakePair(Failure::Exception(), NULL);
9466 }
9467
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009468 // Deal with a normal eval call with a string argument. Compile it
9469 // and return the compiled function bound in the local context.
9470 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9471 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009472 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009473 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009474 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009475 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009476 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009477 Handle<JSFunction> compiled =
9478 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009479 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009480 return MakePair(*compiled, *receiver);
9481}
9482
9483
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009484RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009485 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009486
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009487 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009488 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009489
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009490 // If "eval" didn't refer to the original GlobalEval, it's not a
9491 // direct call to eval.
9492 // (And even if it is, but the first argument isn't a string, just let
9493 // execution default to an indirect call to eval, which will also return
9494 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009495 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009496 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009497 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009498 }
9499
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009500 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009501 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009502 return CompileGlobalEval(isolate,
9503 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009504 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009505 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009506 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009507}
9508
9509
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009510RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009511 // This utility adjusts the property attributes for newly created Function
9512 // object ("new Function(...)") by changing the map.
9513 // All it does is changing the prototype property to enumerable
9514 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009515 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009516 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009517 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009518
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009519 Handle<Map> map = func->shared()->is_classic_mode()
9520 ? isolate->function_instance_map()
9521 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009522
9523 ASSERT(func->map()->instance_type() == map->instance_type());
9524 ASSERT(func->map()->instance_size() == map->instance_size());
9525 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009526 return *func;
9527}
9528
9529
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009530RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009531 // Allocate a block of memory in NewSpace (filled with a filler).
9532 // Use as fallback for allocation in generated code when NewSpace
9533 // is full.
9534 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009535 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009536 int size = size_smi->value();
9537 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9538 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009539 Heap* heap = isolate->heap();
9540 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009541 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009542 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009543 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009544 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009545 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009546 }
9547 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009548 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009549}
9550
9551
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009552// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009553// array. Returns true if the element was pushed on the stack and
9554// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009555RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009556 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009557 CONVERT_ARG_CHECKED(JSArray, array, 0);
9558 CONVERT_ARG_CHECKED(JSObject, element, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009559 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009560 int length = Smi::cast(array->length())->value();
9561 FixedArray* elements = FixedArray::cast(array->elements());
9562 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009563 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009564 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009565 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009566 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009567 { MaybeObject* maybe_obj =
9568 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009569 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9570 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009571 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009572}
9573
9574
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009575/**
9576 * A simple visitor visits every element of Array's.
9577 * The backend storage can be a fixed array for fast elements case,
9578 * or a dictionary for sparse array. Since Dictionary is a subtype
9579 * of FixedArray, the class can be used by both fast and slow cases.
9580 * The second parameter of the constructor, fast_elements, specifies
9581 * whether the storage is a FixedArray or Dictionary.
9582 *
9583 * An index limit is used to deal with the situation that a result array
9584 * length overflows 32-bit non-negative integer.
9585 */
9586class ArrayConcatVisitor {
9587 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009588 ArrayConcatVisitor(Isolate* isolate,
9589 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009590 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009591 isolate_(isolate),
9592 storage_(Handle<FixedArray>::cast(
9593 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009594 index_offset_(0u),
9595 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009596
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009597 ~ArrayConcatVisitor() {
9598 clear_storage();
9599 }
9600
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009601 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009602 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009603 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009604
9605 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009606 if (index < static_cast<uint32_t>(storage_->length())) {
9607 storage_->set(index, *elm);
9608 return;
9609 }
9610 // Our initial estimate of length was foiled, possibly by
9611 // getters on the arrays increasing the length of later arrays
9612 // during iteration.
9613 // This shouldn't happen in anything but pathological cases.
9614 SetDictionaryMode(index);
9615 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009616 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009617 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009618 Handle<SeededNumberDictionary> dict(
9619 SeededNumberDictionary::cast(*storage_));
9620 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009621 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009622 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009623 // Dictionary needed to grow.
9624 clear_storage();
9625 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009626 }
9627}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009628
9629 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009630 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9631 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009632 } else {
9633 index_offset_ += delta;
9634 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009635 }
9636
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009637 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009638 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009639 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009640 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009641 Handle<Map> map;
9642 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009643 map = isolate_->factory()->GetElementsTransitionMap(array,
9644 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009645 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009646 map = isolate_->factory()->GetElementsTransitionMap(array,
9647 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009648 }
9649 array->set_map(*map);
9650 array->set_length(*length);
9651 array->set_elements(*storage_);
9652 return array;
9653 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009654
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009655 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009656 // Convert storage to dictionary mode.
9657 void SetDictionaryMode(uint32_t index) {
9658 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009659 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009660 Handle<SeededNumberDictionary> slow_storage(
9661 isolate_->factory()->NewSeededNumberDictionary(
9662 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009663 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9664 for (uint32_t i = 0; i < current_length; i++) {
9665 HandleScope loop_scope;
9666 Handle<Object> element(current_storage->get(i));
9667 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009668 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009669 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009670 if (!new_storage.is_identical_to(slow_storage)) {
9671 slow_storage = loop_scope.CloseAndEscape(new_storage);
9672 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009673 }
9674 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009675 clear_storage();
9676 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009677 fast_elements_ = false;
9678 }
9679
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009680 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009681 isolate_->global_handles()->Destroy(
9682 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009683 }
9684
9685 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009686 storage_ = Handle<FixedArray>::cast(
9687 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009688 }
9689
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009690 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009691 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009692 // Index after last seen index. Always less than or equal to
9693 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009694 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009695 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009696};
9697
9698
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009699static uint32_t EstimateElementCount(Handle<JSArray> array) {
9700 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9701 int element_count = 0;
9702 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009703 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009704 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009705 // Fast elements can't have lengths that are not representable by
9706 // a 32-bit signed integer.
9707 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9708 int fast_length = static_cast<int>(length);
9709 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9710 for (int i = 0; i < fast_length; i++) {
9711 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009712 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009713 break;
9714 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009715 case FAST_DOUBLE_ELEMENTS:
9716 // TODO(1810): Decide if it's worthwhile to implement this.
9717 UNREACHABLE();
9718 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009719 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009720 Handle<SeededNumberDictionary> dictionary(
9721 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009722 int capacity = dictionary->Capacity();
9723 for (int i = 0; i < capacity; i++) {
9724 Handle<Object> key(dictionary->KeyAt(i));
9725 if (dictionary->IsKey(*key)) {
9726 element_count++;
9727 }
9728 }
9729 break;
9730 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009731 case NON_STRICT_ARGUMENTS_ELEMENTS:
9732 case EXTERNAL_BYTE_ELEMENTS:
9733 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9734 case EXTERNAL_SHORT_ELEMENTS:
9735 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9736 case EXTERNAL_INT_ELEMENTS:
9737 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9738 case EXTERNAL_FLOAT_ELEMENTS:
9739 case EXTERNAL_DOUBLE_ELEMENTS:
9740 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009741 // External arrays are always dense.
9742 return length;
9743 }
9744 // As an estimate, we assume that the prototype doesn't contain any
9745 // inherited elements.
9746 return element_count;
9747}
9748
9749
9750
9751template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009752static void IterateExternalArrayElements(Isolate* isolate,
9753 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009754 bool elements_are_ints,
9755 bool elements_are_guaranteed_smis,
9756 ArrayConcatVisitor* visitor) {
9757 Handle<ExternalArrayClass> array(
9758 ExternalArrayClass::cast(receiver->elements()));
9759 uint32_t len = static_cast<uint32_t>(array->length());
9760
9761 ASSERT(visitor != NULL);
9762 if (elements_are_ints) {
9763 if (elements_are_guaranteed_smis) {
9764 for (uint32_t j = 0; j < len; j++) {
9765 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009766 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009767 visitor->visit(j, e);
9768 }
9769 } else {
9770 for (uint32_t j = 0; j < len; j++) {
9771 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009772 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009773 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9774 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9775 visitor->visit(j, e);
9776 } else {
9777 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009778 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009779 visitor->visit(j, e);
9780 }
9781 }
9782 }
9783 } else {
9784 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009785 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009786 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009787 visitor->visit(j, e);
9788 }
9789 }
9790}
9791
9792
9793// Used for sorting indices in a List<uint32_t>.
9794static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9795 uint32_t a = *ap;
9796 uint32_t b = *bp;
9797 return (a == b) ? 0 : (a < b) ? -1 : 1;
9798}
9799
9800
9801static void CollectElementIndices(Handle<JSObject> object,
9802 uint32_t range,
9803 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009804 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009805 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009806 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009807 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009808 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9809 uint32_t length = static_cast<uint32_t>(elements->length());
9810 if (range < length) length = range;
9811 for (uint32_t i = 0; i < length; i++) {
9812 if (!elements->get(i)->IsTheHole()) {
9813 indices->Add(i);
9814 }
9815 }
9816 break;
9817 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009818 case FAST_DOUBLE_ELEMENTS: {
9819 // TODO(1810): Decide if it's worthwhile to implement this.
9820 UNREACHABLE();
9821 break;
9822 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009823 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009824 Handle<SeededNumberDictionary> dict(
9825 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009826 uint32_t capacity = dict->Capacity();
9827 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009828 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009829 Handle<Object> k(dict->KeyAt(j));
9830 if (dict->IsKey(*k)) {
9831 ASSERT(k->IsNumber());
9832 uint32_t index = static_cast<uint32_t>(k->Number());
9833 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009834 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009835 }
9836 }
9837 }
9838 break;
9839 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009840 default: {
9841 int dense_elements_length;
9842 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009843 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009844 dense_elements_length =
9845 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009846 break;
9847 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009848 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009849 dense_elements_length =
9850 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009851 break;
9852 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009853 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009854 dense_elements_length =
9855 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009856 break;
9857 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009858 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009859 dense_elements_length =
9860 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009861 break;
9862 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009863 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009864 dense_elements_length =
9865 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009866 break;
9867 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009868 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009869 dense_elements_length =
9870 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009871 break;
9872 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009873 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009874 dense_elements_length =
9875 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009876 break;
9877 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009878 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009879 dense_elements_length =
9880 ExternalFloatArray::cast(object->elements())->length();
9881 break;
9882 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009883 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009884 dense_elements_length =
9885 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009886 break;
9887 }
9888 default:
9889 UNREACHABLE();
9890 dense_elements_length = 0;
9891 break;
9892 }
9893 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9894 if (range <= length) {
9895 length = range;
9896 // We will add all indices, so we might as well clear it first
9897 // and avoid duplicates.
9898 indices->Clear();
9899 }
9900 for (uint32_t i = 0; i < length; i++) {
9901 indices->Add(i);
9902 }
9903 if (length == range) return; // All indices accounted for already.
9904 break;
9905 }
9906 }
9907
9908 Handle<Object> prototype(object->GetPrototype());
9909 if (prototype->IsJSObject()) {
9910 // The prototype will usually have no inherited element indices,
9911 // but we have to check.
9912 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9913 }
9914}
9915
9916
9917/**
9918 * A helper function that visits elements of a JSArray in numerical
9919 * order.
9920 *
9921 * The visitor argument called for each existing element in the array
9922 * with the element index and the element's value.
9923 * Afterwards it increments the base-index of the visitor by the array
9924 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009925 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009926 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009927static bool IterateElements(Isolate* isolate,
9928 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009929 ArrayConcatVisitor* visitor) {
9930 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9931 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009932 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009933 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009934 // Run through the elements FixedArray and use HasElement and GetElement
9935 // to check the prototype for missing elements.
9936 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9937 int fast_length = static_cast<int>(length);
9938 ASSERT(fast_length <= elements->length());
9939 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009940 HandleScope loop_scope(isolate);
9941 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009942 if (!element_value->IsTheHole()) {
9943 visitor->visit(j, element_value);
9944 } else if (receiver->HasElement(j)) {
9945 // Call GetElement on receiver, not its prototype, or getters won't
9946 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009947 element_value = Object::GetElement(receiver, j);
9948 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009949 visitor->visit(j, element_value);
9950 }
9951 }
9952 break;
9953 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009954 case FAST_DOUBLE_ELEMENTS: {
9955 // TODO(1810): Decide if it's worthwhile to implement this.
9956 UNREACHABLE();
9957 break;
9958 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009959 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009960 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009961 List<uint32_t> indices(dict->Capacity() / 2);
9962 // Collect all indices in the object and the prototypes less
9963 // than length. This might introduce duplicates in the indices list.
9964 CollectElementIndices(receiver, length, &indices);
9965 indices.Sort(&compareUInt32);
9966 int j = 0;
9967 int n = indices.length();
9968 while (j < n) {
9969 HandleScope loop_scope;
9970 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009971 Handle<Object> element = Object::GetElement(receiver, index);
9972 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009973 visitor->visit(index, element);
9974 // Skip to next different index (i.e., omit duplicates).
9975 do {
9976 j++;
9977 } while (j < n && indices[j] == index);
9978 }
9979 break;
9980 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009981 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009982 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9983 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009984 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009985 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009986 visitor->visit(j, e);
9987 }
9988 break;
9989 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009990 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009991 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009992 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009993 break;
9994 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009995 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009996 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009997 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009998 break;
9999 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010000 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010001 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010002 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010003 break;
10004 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010005 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010006 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010007 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010008 break;
10009 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010010 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010011 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010012 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010013 break;
10014 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010015 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010016 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010017 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010018 break;
10019 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010020 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010021 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010022 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010023 break;
10024 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010025 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010026 IterateExternalArrayElements<ExternalDoubleArray, double>(
10027 isolate, receiver, false, false, visitor);
10028 break;
10029 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010030 default:
10031 UNREACHABLE();
10032 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010033 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010034 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010035 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010036}
10037
10038
10039/**
10040 * Array::concat implementation.
10041 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010042 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010043 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010044 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010045RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010046 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010047 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010048
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010049 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010050 int argument_count = static_cast<int>(arguments->length()->Number());
10051 RUNTIME_ASSERT(arguments->HasFastElements());
10052 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010053
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010054 // Pass 1: estimate the length and number of elements of the result.
10055 // The actual length can be larger if any of the arguments have getters
10056 // that mutate other arguments (but will otherwise be precise).
10057 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010058
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010059 uint32_t estimate_result_length = 0;
10060 uint32_t estimate_nof_elements = 0;
10061 {
10062 for (int i = 0; i < argument_count; i++) {
10063 HandleScope loop_scope;
10064 Handle<Object> obj(elements->get(i));
10065 uint32_t length_estimate;
10066 uint32_t element_estimate;
10067 if (obj->IsJSArray()) {
10068 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010069 // TODO(1810): Find out if it's worthwhile to properly support
10070 // arbitrary ElementsKinds. For now, pessimistically transition to
10071 // FAST_ELEMENTS.
10072 if (array->HasFastDoubleElements()) {
10073 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010074 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010075 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010076 length_estimate =
10077 static_cast<uint32_t>(array->length()->Number());
10078 element_estimate =
10079 EstimateElementCount(array);
10080 } else {
10081 length_estimate = 1;
10082 element_estimate = 1;
10083 }
10084 // Avoid overflows by capping at kMaxElementCount.
10085 if (JSObject::kMaxElementCount - estimate_result_length <
10086 length_estimate) {
10087 estimate_result_length = JSObject::kMaxElementCount;
10088 } else {
10089 estimate_result_length += length_estimate;
10090 }
10091 if (JSObject::kMaxElementCount - estimate_nof_elements <
10092 element_estimate) {
10093 estimate_nof_elements = JSObject::kMaxElementCount;
10094 } else {
10095 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010096 }
10097 }
10098 }
10099
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010100 // If estimated number of elements is more than half of length, a
10101 // fixed array (fast case) is more time and space-efficient than a
10102 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010103 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010104
10105 Handle<FixedArray> storage;
10106 if (fast_case) {
10107 // The backing storage array must have non-existing elements to
10108 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010109 storage = isolate->factory()->NewFixedArrayWithHoles(
10110 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010111 } else {
10112 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10113 uint32_t at_least_space_for = estimate_nof_elements +
10114 (estimate_nof_elements >> 2);
10115 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010116 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010117 }
10118
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010119 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010120
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010121 for (int i = 0; i < argument_count; i++) {
10122 Handle<Object> obj(elements->get(i));
10123 if (obj->IsJSArray()) {
10124 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010125 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010126 return Failure::Exception();
10127 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010128 } else {
10129 visitor.visit(0, obj);
10130 visitor.increase_index_offset(1);
10131 }
10132 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010133
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010134 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010135}
10136
10137
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010138// This will not allocate (flatten the string), but it may run
10139// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010140RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010141 NoHandleAllocation ha;
10142 ASSERT(args.length() == 1);
10143
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010144 CONVERT_ARG_CHECKED(String, string, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010145 StringInputBuffer buffer(string);
10146 while (buffer.has_more()) {
10147 uint16_t character = buffer.GetNext();
10148 PrintF("%c", character);
10149 }
10150 return string;
10151}
10152
ager@chromium.org5ec48922009-05-05 07:25:34 +000010153// Moves all own elements of an object, that are below a limit, to positions
10154// starting at zero. All undefined values are placed after non-undefined values,
10155// and are followed by non-existing element. Does not change the length
10156// property.
10157// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010158RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010159 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010160 CONVERT_ARG_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010161 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10162 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010163}
10164
10165
10166// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010167RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010168 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010169 CONVERT_ARG_CHECKED(JSArray, from, 0);
10170 CONVERT_ARG_CHECKED(JSArray, to, 1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010171 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010172 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010173 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010174 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10175 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010176 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010177 } else if (new_elements->map() ==
10178 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010179 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010180 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010181 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010182 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010183 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010184 Object* new_map;
10185 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010186 to->set_map(Map::cast(new_map));
10187 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010188 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010189 Object* obj;
10190 { MaybeObject* maybe_obj = from->ResetElements();
10191 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10192 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010193 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010194 return to;
10195}
10196
10197
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010198// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010199RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010200 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010201 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010202 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010203 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010204 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10205 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010206 } else if (object->IsJSArray()) {
10207 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010208 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010209 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010210 }
10211}
10212
10213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010214RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010215 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010216
10217 ASSERT_EQ(3, args.length());
10218
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010219 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010220 Handle<Object> key1 = args.at<Object>(1);
10221 Handle<Object> key2 = args.at<Object>(2);
10222
10223 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010224 if (!key1->ToArrayIndex(&index1)
10225 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010226 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010227 }
10228
ager@chromium.orgac091b72010-05-05 07:34:42 +000010229 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010230 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010231 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010232 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010233 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010234
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010235 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000010236 isolate, JSObject::SetElement(jsobject, index1, tmp2, NONE, kStrictMode));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010237 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000010238 isolate, JSObject::SetElement(jsobject, index2, tmp1, NONE, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010239
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010240 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010241}
10242
10243
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010244// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010245// might have elements. Can either return keys (positive integers) or
10246// intervals (pair of a negative integer (-start-1) followed by a
10247// positive (length)) or undefined values.
10248// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010249RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010250 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010251 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010252 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010253 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010254 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010255 // Create an array and get all the keys into it, then remove all the
10256 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010257 bool threw = false;
10258 Handle<FixedArray> keys =
10259 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10260 if (threw) return Failure::Exception();
10261
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010262 int keys_length = keys->length();
10263 for (int i = 0; i < keys_length; i++) {
10264 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010265 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010266 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010267 // Zap invalid keys.
10268 keys->set_undefined(i);
10269 }
10270 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010271 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010272 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010273 ASSERT(array->HasFastElements() ||
10274 array->HasFastSmiOnlyElements() ||
10275 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010276 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010277 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010278 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010279 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010280 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010281 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010282 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010283 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010284 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010285 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010286 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010287 }
10288}
10289
10290
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010291RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010292 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010293 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10294 CONVERT_ARG_CHECKED(String, name, 1);
10295 CONVERT_SMI_ARG_CHECKED(flag, 2);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000010296 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
10297 return obj->LookupAccessor(name, component);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010298}
10299
10300
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010301#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010302RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010303 ASSERT(args.length() == 0);
10304 return Execution::DebugBreakHelper();
10305}
10306
10307
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010308// Helper functions for wrapping and unwrapping stack frame ids.
10309static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010310 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010311 return Smi::FromInt(id >> 2);
10312}
10313
10314
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010315static StackFrame::Id UnwrapFrameId(int wrapped) {
10316 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010317}
10318
10319
10320// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010321// args[0]: debug event listener function to set or null or undefined for
10322// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010323// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010324RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010325 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010326 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10327 args[0]->IsUndefined() ||
10328 args[0]->IsNull());
10329 Handle<Object> callback = args.at<Object>(0);
10330 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010331 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010332
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010333 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010334}
10335
10336
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010337RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010338 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010339 isolate->stack_guard()->DebugBreak();
10340 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010341}
10342
10343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010344static MaybeObject* DebugLookupResultValue(Heap* heap,
10345 Object* receiver,
10346 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010347 LookupResult* result,
10348 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010349 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010350 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010351 case NORMAL:
10352 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010353 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010354 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010355 }
10356 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010357 case FIELD:
10358 value =
10359 JSObject::cast(
10360 result->holder())->FastPropertyAt(result->GetFieldIndex());
10361 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010362 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010363 }
10364 return value;
10365 case CONSTANT_FUNCTION:
10366 return result->GetConstantFunction();
10367 case CALLBACKS: {
10368 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010369 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010370 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10371 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010372 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010373 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010374 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010375 maybe_value = heap->isolate()->pending_exception();
10376 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010377 if (caught_exception != NULL) {
10378 *caught_exception = true;
10379 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010380 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010381 }
10382 return value;
10383 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010384 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010385 }
10386 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010387 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010388 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010389 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010390 case CONSTANT_TRANSITION:
10391 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010392 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010393 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010394 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010395 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010396 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010397 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010398 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010399}
10400
10401
ager@chromium.org32912102009-01-16 10:38:43 +000010402// Get debugger related details for an object property.
10403// args[0]: object holding property
10404// args[1]: name of the property
10405//
10406// The array returned contains the following information:
10407// 0: Property value
10408// 1: Property details
10409// 2: Property value is exception
10410// 3: Getter function if defined
10411// 4: Setter function if defined
10412// Items 2-4 are only filled if the property has either a getter or a setter
10413// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010414RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010415 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010416
10417 ASSERT(args.length() == 2);
10418
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010419 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10420 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010421
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010422 // Make sure to set the current context to the context before the debugger was
10423 // entered (if the debugger is entered). The reason for switching context here
10424 // is that for some property lookups (accessors and interceptors) callbacks
10425 // into the embedding application can occour, and the embedding application
10426 // could have the assumption that its own global context is the current
10427 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010428 SaveContext save(isolate);
10429 if (isolate->debug()->InDebugger()) {
10430 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010431 }
10432
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010433 // Skip the global proxy as it has no properties and always delegates to the
10434 // real global object.
10435 if (obj->IsJSGlobalProxy()) {
10436 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10437 }
10438
10439
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010440 // Check if the name is trivially convertible to an index and get the element
10441 // if so.
10442 uint32_t index;
10443 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010444 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010445 Object* element_or_char;
10446 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010447 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010448 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10449 return maybe_element_or_char;
10450 }
10451 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010452 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010453 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010454 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010455 }
10456
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010457 // Find the number of objects making up this.
10458 int length = LocalPrototypeChainLength(*obj);
10459
10460 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010461 Handle<JSObject> jsproto = obj;
10462 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010463 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010464 jsproto->LocalLookup(*name, &result);
10465 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010466 // LookupResult is not GC safe as it holds raw object pointers.
10467 // GC can happen later in this code so put the required fields into
10468 // local variables using handles when required for later use.
10469 PropertyType result_type = result.type();
10470 Handle<Object> result_callback_obj;
10471 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010472 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10473 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010474 }
10475 Smi* property_details = result.GetPropertyDetails().AsSmi();
10476 // DebugLookupResultValue can cause GC so details from LookupResult needs
10477 // to be copied to handles before this.
10478 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010479 Object* raw_value;
10480 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010481 DebugLookupResultValue(isolate->heap(), *obj, *name,
10482 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010483 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10484 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010485 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010486
10487 // If the callback object is a fixed array then it contains JavaScript
10488 // getter and/or setter.
10489 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010490 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010491 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010492 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010493 details->set(0, *value);
10494 details->set(1, property_details);
10495 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010496 details->set(2, isolate->heap()->ToBoolean(caught_exception));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010497 details->set(3, AccessorPair::cast(*result_callback_obj)->getter());
10498 details->set(4, AccessorPair::cast(*result_callback_obj)->setter());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010499 }
10500
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010501 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010502 }
10503 if (i < length - 1) {
10504 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10505 }
10506 }
10507
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010508 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010509}
10510
10511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010512RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010513 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010514
10515 ASSERT(args.length() == 2);
10516
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010517 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10518 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010519
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010520 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010521 obj->Lookup(*name, &result);
10522 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010523 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010524 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010525 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010526}
10527
10528
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010529// Return the property type calculated from the property details.
10530// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010531RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010532 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010533 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10534 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010535}
10536
10537
10538// Return the property attribute calculated from the property details.
10539// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010540RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010541 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010542 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10543 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010544}
10545
10546
10547// Return the property insertion index calculated from the property details.
10548// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010549RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010550 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010551 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10552 return Smi::FromInt(details.index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010553}
10554
10555
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010556// Return property value from named interceptor.
10557// args[0]: object
10558// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010559RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010560 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010561 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010562 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010563 RUNTIME_ASSERT(obj->HasNamedInterceptor());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010564 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010565
10566 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010567 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010568}
10569
10570
10571// Return element value from indexed interceptor.
10572// args[0]: object
10573// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010574RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010575 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010576 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010577 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010578 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10579 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10580
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010581 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010582}
10583
10584
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010585RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010586 ASSERT(args.length() >= 1);
10587 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010588 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010589 if (isolate->debug()->break_id() == 0 ||
10590 break_id != isolate->debug()->break_id()) {
10591 return isolate->Throw(
10592 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010593 }
10594
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010595 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010596}
10597
10598
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010599RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010600 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010601 ASSERT(args.length() == 1);
10602
10603 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010604 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010605 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10606 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010607 if (!maybe_result->ToObject(&result)) return maybe_result;
10608 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010609
10610 // Count all frames which are relevant to debugging stack trace.
10611 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010612 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010613 if (id == StackFrame::NO_ID) {
10614 // If there is no JavaScript stack frame count is 0.
10615 return Smi::FromInt(0);
10616 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010617
10618 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10619 n += it.frame()->GetInlineCount();
10620 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010621 return Smi::FromInt(n);
10622}
10623
10624
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010625class FrameInspector {
10626 public:
10627 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010628 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010629 Isolate* isolate)
10630 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10631 // Calculate the deoptimized frame.
10632 if (frame->is_optimized()) {
10633 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010634 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010635 }
10636 has_adapted_arguments_ = frame_->has_adapted_arguments();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010637 is_bottommost_ = inlined_jsframe_index == 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010638 is_optimized_ = frame_->is_optimized();
10639 }
10640
10641 ~FrameInspector() {
10642 // Get rid of the calculated deoptimized frame if any.
10643 if (deoptimized_frame_ != NULL) {
10644 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10645 isolate_);
10646 }
10647 }
10648
10649 int GetParametersCount() {
10650 return is_optimized_
10651 ? deoptimized_frame_->parameters_count()
10652 : frame_->ComputeParametersCount();
10653 }
10654 int expression_count() { return deoptimized_frame_->expression_count(); }
10655 Object* GetFunction() {
10656 return is_optimized_
10657 ? deoptimized_frame_->GetFunction()
10658 : frame_->function();
10659 }
10660 Object* GetParameter(int index) {
10661 return is_optimized_
10662 ? deoptimized_frame_->GetParameter(index)
10663 : frame_->GetParameter(index);
10664 }
10665 Object* GetExpression(int index) {
10666 return is_optimized_
10667 ? deoptimized_frame_->GetExpression(index)
10668 : frame_->GetExpression(index);
10669 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010670 int GetSourcePosition() {
10671 return is_optimized_
10672 ? deoptimized_frame_->GetSourcePosition()
10673 : frame_->LookupCode()->SourcePosition(frame_->pc());
10674 }
ulan@chromium.org967e2702012-02-28 09:49:15 +000010675 bool IsConstructor() {
10676 return is_optimized_ && !is_bottommost_
10677 ? deoptimized_frame_->HasConstructStub()
10678 : frame_->IsConstructor();
10679 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010680
10681 // To inspect all the provided arguments the frame might need to be
10682 // replaced with the arguments frame.
10683 void SetArgumentsFrame(JavaScriptFrame* frame) {
10684 ASSERT(has_adapted_arguments_);
10685 frame_ = frame;
10686 is_optimized_ = frame_->is_optimized();
10687 ASSERT(!is_optimized_);
10688 }
10689
10690 private:
10691 JavaScriptFrame* frame_;
10692 DeoptimizedFrameInfo* deoptimized_frame_;
10693 Isolate* isolate_;
10694 bool is_optimized_;
ulan@chromium.org967e2702012-02-28 09:49:15 +000010695 bool is_bottommost_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010696 bool has_adapted_arguments_;
10697
10698 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10699};
10700
10701
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010702static const int kFrameDetailsFrameIdIndex = 0;
10703static const int kFrameDetailsReceiverIndex = 1;
10704static const int kFrameDetailsFunctionIndex = 2;
10705static const int kFrameDetailsArgumentCountIndex = 3;
10706static const int kFrameDetailsLocalCountIndex = 4;
10707static const int kFrameDetailsSourcePositionIndex = 5;
10708static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010709static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010710static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010711static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010712
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010713
10714static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10715 JavaScriptFrame* frame) {
10716 SaveContext* save = isolate->save_context();
10717 while (save != NULL && !save->IsBelowFrame(frame)) {
10718 save = save->prev();
10719 }
10720 ASSERT(save != NULL);
10721 return save;
10722}
10723
10724
ulan@chromium.org967e2702012-02-28 09:49:15 +000010725RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
10726 NoHandleAllocation ha;
10727 ASSERT(args.length() == 0);
10728 JavaScriptFrameIterator it(isolate);
10729 JavaScriptFrame* frame = it.frame();
10730 FrameInspector frame_inspector(frame, frame->GetInlineCount() - 1, isolate);
10731 return isolate->heap()->ToBoolean(frame_inspector.IsConstructor());
10732}
10733
10734
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010735// Return an array with frame details
10736// args[0]: number: break id
10737// args[1]: number: frame index
10738//
10739// The array returned contains the following information:
10740// 0: Frame id
10741// 1: Receiver
10742// 2: Function
10743// 3: Argument count
10744// 4: Local count
10745// 5: Source position
10746// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010747// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010748// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010749// Arguments name, value
10750// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010751// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010752RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010753 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010754 ASSERT(args.length() == 2);
10755
10756 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010757 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010758 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10759 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010760 if (!maybe_check->ToObject(&check)) return maybe_check;
10761 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010762 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010763 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010764
10765 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010766 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010767 if (id == StackFrame::NO_ID) {
10768 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010769 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010770 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010771
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010772 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010773 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010774 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010775 if (index < count + it.frame()->GetInlineCount()) break;
10776 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010777 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010778 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010779
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010780 bool is_optimized = it.frame()->is_optimized();
10781
10782 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10783 if (is_optimized) {
10784 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010785 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010786 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010787 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010788
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010789 // Traverse the saved contexts chain to find the active context for the
10790 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010791 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010792
10793 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010794 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010795
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010796 // Find source position in unoptimized code.
10797 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010798
ulan@chromium.org967e2702012-02-28 09:49:15 +000010799 // Check for constructor frame.
10800 bool constructor = frame_inspector.IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010801
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010802 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010803 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010804 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010805 Handle<ScopeInfo> scope_info(shared->scope_info());
10806 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010807
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010808 // Get the locals names and values into a temporary array.
10809 //
10810 // TODO(1240907): Hide compiler-introduced stack variables
10811 // (e.g. .result)? For users of the debugger, they will probably be
10812 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010813 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010814 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010815
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010816 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010817 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010818 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010819 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010820 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010821 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010822 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010823 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010824 // Get the context containing declarations.
10825 Handle<Context> context(
10826 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010827 for (; i < scope_info->LocalCount(); ++i) {
10828 Handle<String> name(scope_info->LocalName(i));
10829 VariableMode mode;
10830 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010831 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010832 locals->set(i * 2 + 1, context->get(
10833 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010834 }
10835 }
10836
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010837 // Check whether this frame is positioned at return. If not top
10838 // frame or if the frame is optimized it cannot be at a return.
10839 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010840 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010841 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010842 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010843
10844 // If positioned just before return find the value to be returned and add it
10845 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010846 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010847 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010848 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010849 Address internal_frame_sp = NULL;
10850 while (!it2.done()) {
10851 if (it2.frame()->is_internal()) {
10852 internal_frame_sp = it2.frame()->sp();
10853 } else {
10854 if (it2.frame()->is_java_script()) {
10855 if (it2.frame()->id() == it.frame()->id()) {
10856 // The internal frame just before the JavaScript frame contains the
10857 // value to return on top. A debug break at return will create an
10858 // internal frame to store the return value (eax/rax/r0) before
10859 // entering the debug break exit frame.
10860 if (internal_frame_sp != NULL) {
10861 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010862 Handle<Object>(Memory::Object_at(internal_frame_sp),
10863 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010864 break;
10865 }
10866 }
10867 }
10868
10869 // Indicate that the previous frame was not an internal frame.
10870 internal_frame_sp = NULL;
10871 }
10872 it2.Advance();
10873 }
10874 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010875
10876 // Now advance to the arguments adapter frame (if any). It contains all
10877 // the provided parameters whereas the function frame always have the number
10878 // of arguments matching the functions parameters. The rest of the
10879 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010880 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010881 it.AdvanceToArgumentsFrame();
10882 frame_inspector.SetArgumentsFrame(it.frame());
10883 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010884
10885 // Find the number of arguments to fill. At least fill the number of
10886 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010887 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010888 if (argument_count < frame_inspector.GetParametersCount()) {
10889 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010890 }
10891
10892 // Calculate the size of the result.
10893 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010894 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010895 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010896 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010897
10898 // Add the frame id.
10899 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10900
10901 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010902 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010903
10904 // Add the arguments count.
10905 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10906
10907 // Add the locals count
10908 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010909 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010910
10911 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010912 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010913 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10914 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010915 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010916 }
10917
10918 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010919 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010920
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010921 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010922 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010923
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010924 // Add flags to indicate information on whether this frame is
10925 // bit 0: invoked in the debugger context.
10926 // bit 1: optimized frame.
10927 // bit 2: inlined in optimized frame
10928 int flags = 0;
10929 if (*save->context() == *isolate->debug()->debug_context()) {
10930 flags |= 1 << 0;
10931 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010932 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010933 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010934 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010935 }
10936 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010937
10938 // Fill the dynamic part.
10939 int details_index = kFrameDetailsFirstDynamicIndex;
10940
10941 // Add arguments name and value.
10942 for (int i = 0; i < argument_count; i++) {
10943 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010944 if (i < scope_info->ParameterCount()) {
10945 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010946 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010947 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010948 }
10949
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010950 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010951 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010952 // Get the value from the stack.
10953 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010954 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010955 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010956 }
10957 }
10958
10959 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010960 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010961 details->set(details_index++, locals->get(i));
10962 }
10963
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010964 // Add the value being returned.
10965 if (at_return) {
10966 details->set(details_index++, *return_value);
10967 }
10968
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010969 // Add the receiver (same as in function frame).
10970 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10971 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010972 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010973 if (!receiver->IsJSObject() &&
10974 shared->is_classic_mode() &&
10975 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010976 // If the receiver is not a JSObject and the function is not a
10977 // builtin or strict-mode we have hit an optimization where a
10978 // value object is not converted into a wrapped JS objects. To
10979 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010980 // by creating correct wrapper object based on the calling frame's
10981 // global context.
10982 it.Advance();
10983 Handle<Context> calling_frames_global_context(
10984 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010985 receiver =
10986 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010987 }
10988 details->set(kFrameDetailsReceiverIndex, *receiver);
10989
10990 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010991 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010992}
10993
10994
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010995// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010996static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010997 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010998 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010999 Handle<Context> context,
11000 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011001 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011002 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11003 VariableMode mode;
11004 InitializationFlag init_flag;
11005 int context_index = scope_info->ContextSlotIndex(
11006 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011007
whesse@chromium.org7b260152011-06-20 15:33:18 +000011008 RETURN_IF_EMPTY_HANDLE_VALUE(
11009 isolate,
11010 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011011 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011012 Handle<Object>(context->get(context_index), isolate),
11013 NONE,
11014 kNonStrictMode),
11015 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011016 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011017
11018 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011019}
11020
11021
11022// Create a plain JSObject which materializes the local scope for the specified
11023// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011024static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011025 Isolate* isolate,
11026 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011027 FrameInspector* frame_inspector) {
11028 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011029 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011030 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011031
11032 // Allocate and initialize a JSObject with all the arguments, stack locals
11033 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011034 Handle<JSObject> local_scope =
11035 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011036
11037 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011038 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011039 Handle<Object> value(
11040 i < frame_inspector->GetParametersCount() ?
11041 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
11042
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011043 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011044 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011045 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011046 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011047 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011048 NONE,
11049 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011050 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011051 }
11052
11053 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011054 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011055 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011056 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011057 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011058 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011059 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011060 NONE,
11061 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011062 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011063 }
11064
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011065 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011066 // Third fill all context locals.
11067 Handle<Context> frame_context(Context::cast(frame->context()));
11068 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011069 if (!CopyContextLocalsToScopeObject(
11070 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011071 return Handle<JSObject>();
11072 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011073
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011074 // Finally copy any properties from the function context extension.
11075 // These will be variables introduced by eval.
11076 if (function_context->closure() == *function) {
11077 if (function_context->has_extension() &&
11078 !function_context->IsGlobalContext()) {
11079 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011080 bool threw = false;
11081 Handle<FixedArray> keys =
11082 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11083 if (threw) return Handle<JSObject>();
11084
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011085 for (int i = 0; i < keys->length(); i++) {
11086 // Names of variables introduced by eval are strings.
11087 ASSERT(keys->get(i)->IsString());
11088 Handle<String> key(String::cast(keys->get(i)));
11089 RETURN_IF_EMPTY_HANDLE_VALUE(
11090 isolate,
11091 SetProperty(local_scope,
11092 key,
11093 GetProperty(ext, key),
11094 NONE,
11095 kNonStrictMode),
11096 Handle<JSObject>());
11097 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011098 }
11099 }
11100 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011101
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011102 return local_scope;
11103}
11104
11105
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011106static Handle<JSObject> MaterializeLocalScope(
11107 Isolate* isolate,
11108 JavaScriptFrame* frame,
11109 int inlined_jsframe_index) {
11110 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11111 return MaterializeLocalScopeWithFrameInspector(isolate,
11112 frame,
11113 &frame_inspector);
11114}
11115
11116
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011117// Create a plain JSObject which materializes the closure content for the
11118// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011119static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11120 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011121 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011122
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011123 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011124 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011125
ulan@chromium.org2efb9002012-01-19 15:36:35 +000011126 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011127 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011128 Handle<JSObject> closure_scope =
11129 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011130
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011131 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011132 if (!CopyContextLocalsToScopeObject(
11133 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011134 return Handle<JSObject>();
11135 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011136
11137 // Finally copy any properties from the function context extension. This will
11138 // be variables introduced by eval.
11139 if (context->has_extension()) {
11140 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011141 bool threw = false;
11142 Handle<FixedArray> keys =
11143 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11144 if (threw) return Handle<JSObject>();
11145
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011146 for (int i = 0; i < keys->length(); i++) {
11147 // Names of variables introduced by eval are strings.
11148 ASSERT(keys->get(i)->IsString());
11149 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011150 RETURN_IF_EMPTY_HANDLE_VALUE(
11151 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011152 SetProperty(closure_scope,
11153 key,
11154 GetProperty(ext, key),
11155 NONE,
11156 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011157 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011158 }
11159 }
11160
11161 return closure_scope;
11162}
11163
11164
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011165// Create a plain JSObject which materializes the scope for the specified
11166// catch context.
11167static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11168 Handle<Context> context) {
11169 ASSERT(context->IsCatchContext());
11170 Handle<String> name(String::cast(context->extension()));
11171 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11172 Handle<JSObject> catch_scope =
11173 isolate->factory()->NewJSObject(isolate->object_function());
11174 RETURN_IF_EMPTY_HANDLE_VALUE(
11175 isolate,
11176 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11177 Handle<JSObject>());
11178 return catch_scope;
11179}
11180
11181
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011182// Create a plain JSObject which materializes the block scope for the specified
11183// block context.
11184static Handle<JSObject> MaterializeBlockScope(
11185 Isolate* isolate,
11186 Handle<Context> context) {
11187 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011188 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011189
11190 // Allocate and initialize a JSObject with all the arguments, stack locals
11191 // heap locals and extension properties of the debugged function.
11192 Handle<JSObject> block_scope =
11193 isolate->factory()->NewJSObject(isolate->object_function());
11194
11195 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011196 if (!CopyContextLocalsToScopeObject(
11197 isolate, scope_info, context, block_scope)) {
11198 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011199 }
11200
11201 return block_scope;
11202}
11203
11204
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011205// Create a plain JSObject which materializes the module scope for the specified
11206// module context.
11207static Handle<JSObject> MaterializeModuleScope(
11208 Isolate* isolate,
11209 Handle<Context> context) {
11210 ASSERT(context->IsModuleContext());
11211 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
11212
11213 // Allocate and initialize a JSObject with all the members of the debugged
11214 // module.
11215 Handle<JSObject> module_scope =
11216 isolate->factory()->NewJSObject(isolate->object_function());
11217
11218 // Fill all context locals.
11219 if (!CopyContextLocalsToScopeObject(
11220 isolate, scope_info, context, module_scope)) {
11221 return Handle<JSObject>();
11222 }
11223
11224 return module_scope;
11225}
11226
11227
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011228// Iterate over the actual scopes visible from a stack frame. The iteration
11229// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011230// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011231// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011232class ScopeIterator {
11233 public:
11234 enum ScopeType {
11235 ScopeTypeGlobal = 0,
11236 ScopeTypeLocal,
11237 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011238 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011239 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011240 ScopeTypeBlock,
11241 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011242 };
11243
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011244 ScopeIterator(Isolate* isolate,
11245 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011246 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011247 : isolate_(isolate),
11248 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011249 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011250 function_(JSFunction::cast(frame->function())),
11251 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011252 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011253
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011254 // Catch the case when the debugger stops in an internal function.
11255 Handle<SharedFunctionInfo> shared_info(function_->shared());
11256 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11257 if (shared_info->script() == isolate->heap()->undefined_value()) {
11258 while (context_->closure() == *function_) {
11259 context_ = Handle<Context>(context_->previous(), isolate_);
11260 }
11261 return;
11262 }
11263
11264 // Get the debug info (create it if it does not exist).
11265 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11266 // Return if ensuring debug info failed.
11267 return;
11268 }
11269 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11270
11271 // Find the break point where execution has stopped.
11272 BreakLocationIterator break_location_iterator(debug_info,
11273 ALL_BREAK_LOCATIONS);
11274 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11275 if (break_location_iterator.IsExit()) {
11276 // We are within the return sequence. At the momemt it is not possible to
11277 // get a source position which is consistent with the current scope chain.
11278 // Thus all nested with, catch and block contexts are skipped and we only
11279 // provide the function scope.
11280 if (scope_info->HasContext()) {
11281 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11282 } else {
11283 while (context_->closure() == *function_) {
11284 context_ = Handle<Context>(context_->previous(), isolate_);
11285 }
11286 }
11287 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11288 } else {
11289 // Reparse the code and analyze the scopes.
11290 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11291 Handle<Script> script(Script::cast(shared_info->script()));
11292 Scope* scope = NULL;
11293
11294 // Check whether we are in global, eval or function code.
11295 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11296 if (scope_info->Type() != FUNCTION_SCOPE) {
11297 // Global or eval code.
11298 CompilationInfo info(script);
11299 if (scope_info->Type() == GLOBAL_SCOPE) {
11300 info.MarkAsGlobal();
11301 } else {
11302 ASSERT(scope_info->Type() == EVAL_SCOPE);
11303 info.MarkAsEval();
11304 info.SetCallingContext(Handle<Context>(function_->context()));
11305 }
11306 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11307 scope = info.function()->scope();
11308 }
11309 } else {
11310 // Function code
11311 CompilationInfo info(shared_info);
11312 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11313 scope = info.function()->scope();
11314 }
11315 }
11316
11317 // Retrieve the scope chain for the current position.
11318 if (scope != NULL) {
11319 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11320 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11321 } else {
11322 // A failed reparse indicates that the preparser has diverged from the
11323 // parser or that the preparse data given to the initial parse has been
11324 // faulty. We fail in debug mode but in release mode we only provide the
11325 // information we get from the context chain but nothing about
11326 // completely stack allocated scopes or stack allocated locals.
11327 UNREACHABLE();
11328 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011329 }
11330 }
11331
11332 // More scopes?
11333 bool Done() { return context_.is_null(); }
11334
11335 // Move to the next scope.
11336 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011337 ScopeType scope_type = Type();
11338 if (scope_type == ScopeTypeGlobal) {
11339 // The global scope is always the last in the chain.
11340 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011341 context_ = Handle<Context>();
11342 return;
11343 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011344 if (nested_scope_chain_.is_empty()) {
11345 context_ = Handle<Context>(context_->previous(), isolate_);
11346 } else {
11347 if (nested_scope_chain_.last()->HasContext()) {
11348 ASSERT(context_->previous() != NULL);
11349 context_ = Handle<Context>(context_->previous(), isolate_);
11350 }
11351 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011352 }
11353 }
11354
11355 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011356 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011357 if (!nested_scope_chain_.is_empty()) {
11358 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11359 switch (scope_info->Type()) {
11360 case FUNCTION_SCOPE:
11361 ASSERT(context_->IsFunctionContext() ||
11362 !scope_info->HasContext());
11363 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011364 case MODULE_SCOPE:
11365 ASSERT(context_->IsModuleContext());
11366 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011367 case GLOBAL_SCOPE:
11368 ASSERT(context_->IsGlobalContext());
11369 return ScopeTypeGlobal;
11370 case WITH_SCOPE:
11371 ASSERT(context_->IsWithContext());
11372 return ScopeTypeWith;
11373 case CATCH_SCOPE:
11374 ASSERT(context_->IsCatchContext());
11375 return ScopeTypeCatch;
11376 case BLOCK_SCOPE:
11377 ASSERT(!scope_info->HasContext() ||
11378 context_->IsBlockContext());
11379 return ScopeTypeBlock;
11380 case EVAL_SCOPE:
11381 UNREACHABLE();
11382 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011383 }
11384 if (context_->IsGlobalContext()) {
11385 ASSERT(context_->global()->IsGlobalObject());
11386 return ScopeTypeGlobal;
11387 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011388 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011389 return ScopeTypeClosure;
11390 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011391 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011392 return ScopeTypeCatch;
11393 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011394 if (context_->IsBlockContext()) {
11395 return ScopeTypeBlock;
11396 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011397 if (context_->IsModuleContext()) {
11398 return ScopeTypeModule;
11399 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011400 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011401 return ScopeTypeWith;
11402 }
11403
11404 // Return the JavaScript object with the content of the current scope.
11405 Handle<JSObject> ScopeObject() {
11406 switch (Type()) {
11407 case ScopeIterator::ScopeTypeGlobal:
11408 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011409 case ScopeIterator::ScopeTypeLocal:
11410 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011411 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011412 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011413 case ScopeIterator::ScopeTypeWith:
11414 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011415 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11416 case ScopeIterator::ScopeTypeCatch:
11417 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011418 case ScopeIterator::ScopeTypeClosure:
11419 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011420 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011421 case ScopeIterator::ScopeTypeBlock:
11422 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011423 case ScopeIterator::ScopeTypeModule:
11424 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011425 }
11426 UNREACHABLE();
11427 return Handle<JSObject>();
11428 }
11429
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011430 Handle<ScopeInfo> CurrentScopeInfo() {
11431 if (!nested_scope_chain_.is_empty()) {
11432 return nested_scope_chain_.last();
11433 } else if (context_->IsBlockContext()) {
11434 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11435 } else if (context_->IsFunctionContext()) {
11436 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11437 }
11438 return Handle<ScopeInfo>::null();
11439 }
11440
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011441 // Return the context for this scope. For the local context there might not
11442 // be an actual context.
11443 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011444 if (Type() == ScopeTypeGlobal ||
11445 nested_scope_chain_.is_empty()) {
11446 return context_;
11447 } else if (nested_scope_chain_.last()->HasContext()) {
11448 return context_;
11449 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011450 return Handle<Context>();
11451 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011452 }
11453
11454#ifdef DEBUG
11455 // Debug print of the content of the current scope.
11456 void DebugPrint() {
11457 switch (Type()) {
11458 case ScopeIterator::ScopeTypeGlobal:
11459 PrintF("Global:\n");
11460 CurrentContext()->Print();
11461 break;
11462
11463 case ScopeIterator::ScopeTypeLocal: {
11464 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011465 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011466 if (!CurrentContext().is_null()) {
11467 CurrentContext()->Print();
11468 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011469 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011470 if (extension->IsJSContextExtensionObject()) {
11471 extension->Print();
11472 }
11473 }
11474 }
11475 break;
11476 }
11477
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011478 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011479 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011480 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011481 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011482
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011483 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011484 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011485 CurrentContext()->extension()->Print();
11486 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011487 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011488
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011489 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011490 PrintF("Closure:\n");
11491 CurrentContext()->Print();
11492 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011493 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011494 if (extension->IsJSContextExtensionObject()) {
11495 extension->Print();
11496 }
11497 }
11498 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011499
11500 default:
11501 UNREACHABLE();
11502 }
11503 PrintF("\n");
11504 }
11505#endif
11506
11507 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011508 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011509 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011510 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011511 Handle<JSFunction> function_;
11512 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011513 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011514
11515 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11516};
11517
11518
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011519RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011520 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011521 ASSERT(args.length() == 2);
11522
11523 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011524 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011525 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11526 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011527 if (!maybe_check->ToObject(&check)) return maybe_check;
11528 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011529 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011530
11531 // Get the frame where the debugging is performed.
11532 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011533 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011534 JavaScriptFrame* frame = it.frame();
11535
11536 // Count the visible scopes.
11537 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011538 for (ScopeIterator it(isolate, frame, 0);
11539 !it.Done();
11540 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011541 n++;
11542 }
11543
11544 return Smi::FromInt(n);
11545}
11546
11547
11548static const int kScopeDetailsTypeIndex = 0;
11549static const int kScopeDetailsObjectIndex = 1;
11550static const int kScopeDetailsSize = 2;
11551
11552// Return an array with scope details
11553// args[0]: number: break id
11554// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011555// args[2]: number: inlined frame index
11556// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011557//
11558// The array returned contains the following information:
11559// 0: Scope type
11560// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011561RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011562 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011563 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011564
11565 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011566 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011567 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11568 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011569 if (!maybe_check->ToObject(&check)) return maybe_check;
11570 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011571 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011572 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011573 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011574
11575 // Get the frame where the debugging is performed.
11576 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011577 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011578 JavaScriptFrame* frame = frame_it.frame();
11579
11580 // Find the requested scope.
11581 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011582 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011583 for (; !it.Done() && n < index; it.Next()) {
11584 n++;
11585 }
11586 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011587 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011588 }
11589
11590 // Calculate the size of the result.
11591 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011592 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011593
11594 // Fill in scope details.
11595 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011596 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011597 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011598 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011599
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011600 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011601}
11602
11603
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011604RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011605 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011606 ASSERT(args.length() == 0);
11607
11608#ifdef DEBUG
11609 // Print the scopes for the top frame.
11610 StackFrameLocator locator;
11611 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011612 for (ScopeIterator it(isolate, frame, 0);
11613 !it.Done();
11614 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011615 it.DebugPrint();
11616 }
11617#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011618 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011619}
11620
11621
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011622RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011623 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011624 ASSERT(args.length() == 1);
11625
11626 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011627 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011628 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11629 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011630 if (!maybe_result->ToObject(&result)) return maybe_result;
11631 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011632
11633 // Count all archived V8 threads.
11634 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011635 for (ThreadState* thread =
11636 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011637 thread != NULL;
11638 thread = thread->Next()) {
11639 n++;
11640 }
11641
11642 // Total number of threads is current thread and archived threads.
11643 return Smi::FromInt(n + 1);
11644}
11645
11646
11647static const int kThreadDetailsCurrentThreadIndex = 0;
11648static const int kThreadDetailsThreadIdIndex = 1;
11649static const int kThreadDetailsSize = 2;
11650
11651// Return an array with thread details
11652// args[0]: number: break id
11653// args[1]: number: thread index
11654//
11655// The array returned contains the following information:
11656// 0: Is current thread?
11657// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011658RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011659 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011660 ASSERT(args.length() == 2);
11661
11662 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011663 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011664 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11665 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011666 if (!maybe_check->ToObject(&check)) return maybe_check;
11667 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011668 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11669
11670 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011671 Handle<FixedArray> details =
11672 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011673
11674 // Thread index 0 is current thread.
11675 if (index == 0) {
11676 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011677 details->set(kThreadDetailsCurrentThreadIndex,
11678 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011679 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011680 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011681 } else {
11682 // Find the thread with the requested index.
11683 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011684 ThreadState* thread =
11685 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011686 while (index != n && thread != NULL) {
11687 thread = thread->Next();
11688 n++;
11689 }
11690 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011691 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011692 }
11693
11694 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011695 details->set(kThreadDetailsCurrentThreadIndex,
11696 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011697 details->set(kThreadDetailsThreadIdIndex,
11698 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011699 }
11700
11701 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011702 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011703}
11704
11705
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011706// Sets the disable break state
11707// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011708RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011709 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011710 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011711 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011712 isolate->debug()->set_disable_break(disable_break);
11713 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011714}
11715
11716
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011717RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011718 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011719 ASSERT(args.length() == 1);
11720
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011721 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011722 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011723 // Find the number of break points
11724 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011725 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011726 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011727 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011728 Handle<FixedArray>::cast(break_locations));
11729}
11730
11731
11732// Set a break point in a function
11733// args[0]: function
11734// args[1]: number: break source position (within the function source)
11735// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011736RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011737 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011738 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011739 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011740 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011741 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11742 RUNTIME_ASSERT(source_position >= 0);
11743 Handle<Object> break_point_object_arg = args.at<Object>(2);
11744
11745 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011746 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11747 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011748
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011749 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011750}
11751
11752
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011753Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11754 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011755 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011756 // Iterate the heap looking for SharedFunctionInfo generated from the
11757 // script. The inner most SharedFunctionInfo containing the source position
11758 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011759 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011760 // which is found is not compiled it is compiled and the heap is iterated
11761 // again as the compilation might create inner functions from the newly
11762 // compiled function and the actual requested break point might be in one of
11763 // these functions.
11764 bool done = false;
11765 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011766 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011767 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011768 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011769 { // Extra scope for iterator and no-allocation.
11770 isolate->heap()->EnsureHeapIsIterable();
11771 AssertNoAllocation no_alloc_during_heap_iteration;
11772 HeapIterator iterator;
11773 for (HeapObject* obj = iterator.next();
11774 obj != NULL; obj = iterator.next()) {
11775 if (obj->IsSharedFunctionInfo()) {
11776 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11777 if (shared->script() == *script) {
11778 // If the SharedFunctionInfo found has the requested script data and
11779 // contains the source position it is a candidate.
11780 int start_position = shared->function_token_position();
11781 if (start_position == RelocInfo::kNoPosition) {
11782 start_position = shared->start_position();
11783 }
11784 if (start_position <= position &&
11785 position <= shared->end_position()) {
11786 // If there is no candidate or this function is within the current
11787 // candidate this is the new candidate.
11788 if (target.is_null()) {
11789 target_start_position = start_position;
11790 target = shared;
11791 } else {
11792 if (target_start_position == start_position &&
11793 shared->end_position() == target->end_position()) {
11794 // If a top-level function contain only one function
11795 // declartion the source for the top-level and the
11796 // function is the same. In that case prefer the non
11797 // top-level function.
11798 if (!shared->is_toplevel()) {
11799 target_start_position = start_position;
11800 target = shared;
11801 }
11802 } else if (target_start_position <= start_position &&
11803 shared->end_position() <= target->end_position()) {
11804 // This containment check includes equality as a function
11805 // inside a top-level function can share either start or end
11806 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011807 target_start_position = start_position;
11808 target = shared;
11809 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011810 }
11811 }
11812 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011813 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011814 } // End for loop.
11815 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011816
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011817 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011818 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011819 }
11820
11821 // If the candidate found is compiled we are done. NOTE: when lazy
11822 // compilation of inner functions is introduced some additional checking
11823 // needs to be done here to compile inner functions.
11824 done = target->is_compiled();
11825 if (!done) {
11826 // If the candidate is not compiled compile it to reveal any inner
11827 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011828 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011829 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011830 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011831
11832 return *target;
11833}
11834
11835
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011836// Changes the state of a break point in a script and returns source position
11837// where break point was set. NOTE: Regarding performance see the NOTE for
11838// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011839// args[0]: script to set break point in
11840// args[1]: number: break source position (within the script source)
11841// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011842RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011843 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011844 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011845 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011846 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11847 RUNTIME_ASSERT(source_position >= 0);
11848 Handle<Object> break_point_object_arg = args.at<Object>(2);
11849
11850 // Get the script from the script wrapper.
11851 RUNTIME_ASSERT(wrapper->value()->IsScript());
11852 Handle<Script> script(Script::cast(wrapper->value()));
11853
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011854 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011855 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011856 if (!result->IsUndefined()) {
11857 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11858 // Find position within function. The script position might be before the
11859 // source position of the first function.
11860 int position;
11861 if (shared->start_position() > source_position) {
11862 position = 0;
11863 } else {
11864 position = source_position - shared->start_position();
11865 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011866 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011867 position += shared->start_position();
11868 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011869 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011870 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011871}
11872
11873
11874// Clear a break point
11875// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011876RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011877 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011878 ASSERT(args.length() == 1);
11879 Handle<Object> break_point_object_arg = args.at<Object>(0);
11880
11881 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011882 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011883
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011884 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011885}
11886
11887
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011888// Change the state of break on exceptions.
11889// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11890// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011891RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011892 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011893 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011894 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011895 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011896
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011897 // If the number doesn't match an enum value, the ChangeBreakOnException
11898 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011899 ExceptionBreakType type =
11900 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011901 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011902 isolate->debug()->ChangeBreakOnException(type, enable);
11903 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011904}
11905
11906
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011907// Returns the state of break on exceptions
11908// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011909RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011910 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011911 ASSERT(args.length() == 1);
11912 RUNTIME_ASSERT(args[0]->IsNumber());
11913
11914 ExceptionBreakType type =
11915 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011916 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011917 return Smi::FromInt(result);
11918}
11919
11920
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011921// Prepare for stepping
11922// args[0]: break id for checking execution state
11923// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011924// args[2]: number of times to perform the step, for step out it is the number
11925// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011926RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011927 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011928 ASSERT(args.length() == 3);
11929 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011930 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011931 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11932 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011933 if (!maybe_check->ToObject(&check)) return maybe_check;
11934 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011935 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011936 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011937 }
11938
11939 // Get the step action and check validity.
11940 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11941 if (step_action != StepIn &&
11942 step_action != StepNext &&
11943 step_action != StepOut &&
11944 step_action != StepInMin &&
11945 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011946 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011947 }
11948
11949 // Get the number of steps.
11950 int step_count = NumberToInt32(args[2]);
11951 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011952 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011953 }
11954
ager@chromium.orga1645e22009-09-09 19:27:10 +000011955 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011956 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011957
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011958 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011959 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11960 step_count);
11961 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011962}
11963
11964
11965// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011966RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011967 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011968 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011969 isolate->debug()->ClearStepping();
11970 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011971}
11972
11973
11974// Creates a copy of the with context chain. The copy of the context chain is
11975// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011976static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11977 Handle<JSFunction> function,
11978 Handle<Context> base,
11979 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011980 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011981 HandleScope scope(isolate);
11982 List<Handle<ScopeInfo> > scope_chain;
11983 List<Handle<Context> > context_chain;
11984
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011985 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011986 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11987 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11988 ASSERT(!it.Done());
11989 scope_chain.Add(it.CurrentScopeInfo());
11990 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011991 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011992
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011993 // At the end of the chain. Return the base context to link to.
11994 Handle<Context> context = base;
11995
11996 // Iteratively copy and or materialize the nested contexts.
11997 while (!scope_chain.is_empty()) {
11998 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11999 Handle<Context> current = context_chain.RemoveLast();
12000 ASSERT(!(scope_info->HasContext() & current.is_null()));
12001
12002 if (scope_info->Type() == CATCH_SCOPE) {
12003 Handle<String> name(String::cast(current->extension()));
12004 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
12005 context =
12006 isolate->factory()->NewCatchContext(function,
12007 context,
12008 name,
12009 thrown_object);
12010 } else if (scope_info->Type() == BLOCK_SCOPE) {
12011 // Materialize the contents of the block scope into a JSObject.
12012 Handle<JSObject> block_scope_object =
12013 MaterializeBlockScope(isolate, current);
12014 if (block_scope_object.is_null()) {
12015 return Handle<Context>::null();
12016 }
12017 // Allocate a new function context for the debug evaluation and set the
12018 // extension object.
12019 Handle<Context> new_context =
12020 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12021 function);
12022 new_context->set_extension(*block_scope_object);
12023 new_context->set_previous(*context);
12024 context = new_context;
12025 } else {
12026 ASSERT(scope_info->Type() == WITH_SCOPE);
12027 ASSERT(current->IsWithContext());
12028 Handle<JSObject> extension(JSObject::cast(current->extension()));
12029 context =
12030 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000012031 }
erikcorry0ad885c2011-11-21 13:51:57 +000012032 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012033
12034 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012035}
12036
12037
12038// Helper function to find or create the arguments object for
12039// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012040static Handle<Object> GetArgumentsObject(Isolate* isolate,
12041 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012042 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012043 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012044 Handle<Context> function_context) {
12045 // Try to find the value of 'arguments' to pass as parameter. If it is not
12046 // found (that is the debugged function does not reference 'arguments' and
12047 // does not support eval) then create an 'arguments' object.
12048 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012049 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012050 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012051 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012052 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012053 }
12054 }
12055
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012056 if (scope_info->HasHeapAllocatedLocals()) {
12057 VariableMode mode;
12058 InitializationFlag init_flag;
12059 index = scope_info->ContextSlotIndex(
12060 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012061 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012062 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012063 }
12064 }
12065
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012066 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
12067 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012068 Handle<JSObject> arguments =
12069 isolate->factory()->NewArgumentsObject(function, length);
12070 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012071
12072 AssertNoAllocation no_gc;
12073 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012074 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012075 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012076 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012077 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012078 return arguments;
12079}
12080
12081
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012082static const char kSourceStr[] =
12083 "(function(arguments,__source__){return eval(__source__);})";
12084
12085
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012086// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012087// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012088// extension part has all the parameters and locals of the function on the
12089// stack frame. A function which calls eval with the code to evaluate is then
12090// compiled in this context and called in this context. As this context
12091// replaces the context of the function on the stack frame a new (empty)
12092// function is created as well to be used as the closure for the context.
12093// This function and the context acts as replacements for the function on the
12094// stack frame presenting the same view of the values of parameters and
12095// local variables as if the piece of JavaScript was evaluated at the point
12096// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012097RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012098 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012099
12100 // Check the execution state and decode arguments frame and source to be
12101 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012102 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012103 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012104 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12105 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012106 if (!maybe_check_result->ToObject(&check_result)) {
12107 return maybe_check_result;
12108 }
12109 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012110 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012111 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012112 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
12113 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012114 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012115
12116 // Handle the processing of break.
12117 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012118
12119 // Get the frame where the debugging is performed.
12120 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012121 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012122 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012123 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
12124 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012125 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012126
12127 // Traverse the saved contexts chain to find the active context for the
12128 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012129 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12130
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012131 SaveContext savex(isolate);
12132 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012133
12134 // Create the (empty) function replacing the function on the stack frame for
12135 // the purpose of evaluating in the context created below. It is important
12136 // that this function does not describe any parameters and local variables
12137 // in the context. If it does then this will cause problems with the lookup
12138 // in Context::Lookup, where context slots for parameters and local variables
12139 // are looked at before the extension object.
12140 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012141 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12142 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012143 go_between->set_context(function->context());
12144#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012145 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12146 ASSERT(go_between_scope_info->ParameterCount() == 0);
12147 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012148#endif
12149
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012150 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012151 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
12152 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012153 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012154
12155 // Allocate a new context for the debug evaluation and set the extension
12156 // object build.
12157 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012158 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12159 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012160 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012161 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012162 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012163 Handle<Context> function_context;
12164 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012165 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012166 function_context = Handle<Context>(frame_context->declaration_context());
12167 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012168 context = CopyNestedScopeContextChain(isolate,
12169 go_between,
12170 context,
12171 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012172 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012173
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012174 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012175 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012176 context =
12177 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012178 }
12179
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012180 // Wrap the evaluation statement in a new function compiled in the newly
12181 // created context. The function has one parameter which has to be called
12182 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012183 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012184 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012185
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012186 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012187 isolate->factory()->NewStringFromAscii(
12188 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012189
12190 // Currently, the eval code will be executed in non-strict mode,
12191 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012192 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012193 Compiler::CompileEval(function_source,
12194 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012195 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012196 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012197 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012198 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012199 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012200 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012201
12202 // Invoke the result of the compilation to get the evaluation function.
12203 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012204 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012205 Handle<Object> evaluation_function =
12206 Execution::Call(compiled_function, receiver, 0, NULL,
12207 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012208 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012209
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012210 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012211 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012212 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012213 scope_info,
12214 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012215
12216 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012217 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012218 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012219 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12220 receiver,
12221 ARRAY_SIZE(argv),
12222 argv,
12223 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012224 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012225
12226 // Skip the global proxy as it has no properties and always delegates to the
12227 // real global object.
12228 if (result->IsJSGlobalProxy()) {
12229 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12230 }
12231
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012232 return *result;
12233}
12234
12235
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012236RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012237 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012238
12239 // Check the execution state and decode arguments frame and source to be
12240 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012241 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012242 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012243 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12244 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012245 if (!maybe_check_result->ToObject(&check_result)) {
12246 return maybe_check_result;
12247 }
12248 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012249 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
12250 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012251 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012252
12253 // Handle the processing of break.
12254 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012255
12256 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012257 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012258 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012259 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012260 top = top->prev();
12261 }
12262 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012263 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012264 }
12265
12266 // Get the global context now set to the top context from before the
12267 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012268 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012269
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012270 bool is_global = true;
12271
12272 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012273 // Create a new with context with the additional context information between
12274 // the context of the debugged function and the eval code to be executed.
12275 context = isolate->factory()->NewWithContext(
12276 Handle<JSFunction>(context->closure()),
12277 context,
12278 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012279 is_global = false;
12280 }
12281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012282 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012283 // Currently, the eval code will be executed in non-strict mode,
12284 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012285 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012286 Compiler::CompileEval(source,
12287 context,
12288 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012289 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012290 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012291 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012292 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012293 Handle<JSFunction>(
12294 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12295 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012296
12297 // Invoke the result of the compilation to get the evaluation function.
12298 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012299 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012300 Handle<Object> result =
12301 Execution::Call(compiled_function, receiver, 0, NULL,
12302 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012303 // Clear the oneshot breakpoints so that the debugger does not step further.
12304 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012305 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012306 return *result;
12307}
12308
12309
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012310RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012311 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012312 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012313
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012314 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012315 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012316
12317 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012318 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012319 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12320 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12321 // because using
12322 // instances->set(i, *GetScriptWrapper(script))
12323 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012324 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012325 Handle<JSValue> wrapper = GetScriptWrapper(script);
12326 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012327 }
12328
12329 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012330 Handle<JSObject> result =
12331 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012332 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012333 return *result;
12334}
12335
12336
12337// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012338static int DebugReferencedBy(HeapIterator* iterator,
12339 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012340 Object* instance_filter, int max_references,
12341 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012342 JSFunction* arguments_function) {
12343 NoHandleAllocation ha;
12344 AssertNoAllocation no_alloc;
12345
12346 // Iterate the heap.
12347 int count = 0;
12348 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012349 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012350 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012351 (max_references == 0 || count < max_references)) {
12352 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012353 if (heap_obj->IsJSObject()) {
12354 // Skip context extension objects and argument arrays as these are
12355 // checked in the context of functions using them.
12356 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012357 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012358 obj->map()->constructor() == arguments_function) {
12359 continue;
12360 }
12361
12362 // Check if the JS object has a reference to the object looked for.
12363 if (obj->ReferencesObject(target)) {
12364 // Check instance filter if supplied. This is normally used to avoid
12365 // references from mirror objects (see Runtime_IsInPrototypeChain).
12366 if (!instance_filter->IsUndefined()) {
12367 Object* V = obj;
12368 while (true) {
12369 Object* prototype = V->GetPrototype();
12370 if (prototype->IsNull()) {
12371 break;
12372 }
12373 if (instance_filter == prototype) {
12374 obj = NULL; // Don't add this object.
12375 break;
12376 }
12377 V = prototype;
12378 }
12379 }
12380
12381 if (obj != NULL) {
12382 // Valid reference found add to instance array if supplied an update
12383 // count.
12384 if (instances != NULL && count < instances_size) {
12385 instances->set(count, obj);
12386 }
12387 last = obj;
12388 count++;
12389 }
12390 }
12391 }
12392 }
12393
12394 // Check for circular reference only. This can happen when the object is only
12395 // referenced from mirrors and has a circular reference in which case the
12396 // object is not really alive and would have been garbage collected if not
12397 // referenced from the mirror.
12398 if (count == 1 && last == target) {
12399 count = 0;
12400 }
12401
12402 // Return the number of referencing objects found.
12403 return count;
12404}
12405
12406
12407// Scan the heap for objects with direct references to an object
12408// args[0]: the object to find references to
12409// args[1]: constructor function for instances to exclude (Mirror)
12410// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012411RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012412 ASSERT(args.length() == 3);
12413
12414 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012415 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12416 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012417 // The heap iterator reserves the right to do a GC to make the heap iterable.
12418 // Due to the GC above we know it won't need to do that, but it seems cleaner
12419 // to get the heap iterator constructed before we start having unprotected
12420 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012421
12422 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012423 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012424 Object* instance_filter = args[1];
12425 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12426 instance_filter->IsJSObject());
12427 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12428 RUNTIME_ASSERT(max_references >= 0);
12429
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012430
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012431 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012432 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012433 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012434 JSFunction* arguments_function =
12435 JSFunction::cast(arguments_boilerplate->map()->constructor());
12436
12437 // Get the number of referencing objects.
12438 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012439 HeapIterator heap_iterator;
12440 count = DebugReferencedBy(&heap_iterator,
12441 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012442 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012443
12444 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012445 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012446 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012447 if (!maybe_object->ToObject(&object)) return maybe_object;
12448 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012449 FixedArray* instances = FixedArray::cast(object);
12450
12451 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012452 // AllocateFixedArray above does not make the heap non-iterable.
12453 ASSERT(HEAP->IsHeapIterable());
12454 HeapIterator heap_iterator2;
12455 count = DebugReferencedBy(&heap_iterator2,
12456 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012457 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012458
12459 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012460 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012461 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012462 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012463 if (!maybe_result->ToObject(&result)) return maybe_result;
12464 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012465}
12466
12467
12468// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012469static int DebugConstructedBy(HeapIterator* iterator,
12470 JSFunction* constructor,
12471 int max_references,
12472 FixedArray* instances,
12473 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012474 AssertNoAllocation no_alloc;
12475
12476 // Iterate the heap.
12477 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012478 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012479 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012480 (max_references == 0 || count < max_references)) {
12481 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012482 if (heap_obj->IsJSObject()) {
12483 JSObject* obj = JSObject::cast(heap_obj);
12484 if (obj->map()->constructor() == constructor) {
12485 // Valid reference found add to instance array if supplied an update
12486 // count.
12487 if (instances != NULL && count < instances_size) {
12488 instances->set(count, obj);
12489 }
12490 count++;
12491 }
12492 }
12493 }
12494
12495 // Return the number of referencing objects found.
12496 return count;
12497}
12498
12499
12500// Scan the heap for objects constructed by a specific function.
12501// args[0]: the constructor to find instances of
12502// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012503RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012504 ASSERT(args.length() == 2);
12505
12506 // First perform a full GC in order to avoid dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012507 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12508 "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012509
12510 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012511 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012512 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12513 RUNTIME_ASSERT(max_references >= 0);
12514
12515 // Get the number of referencing objects.
12516 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012517 HeapIterator heap_iterator;
12518 count = DebugConstructedBy(&heap_iterator,
12519 constructor,
12520 max_references,
12521 NULL,
12522 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012523
12524 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012525 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012526 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012527 if (!maybe_object->ToObject(&object)) return maybe_object;
12528 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012529 FixedArray* instances = FixedArray::cast(object);
12530
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012531 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012532 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012533 HeapIterator heap_iterator2;
12534 count = DebugConstructedBy(&heap_iterator2,
12535 constructor,
12536 max_references,
12537 instances,
12538 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012539
12540 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012541 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012542 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12543 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012544 if (!maybe_result->ToObject(&result)) return maybe_result;
12545 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012546 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012547}
12548
12549
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012550// Find the effective prototype object as returned by __proto__.
12551// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012552RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012553 ASSERT(args.length() == 1);
12554
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012555 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012556
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012557 // Use the __proto__ accessor.
12558 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012559}
12560
12561
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012562RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012563 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012564 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012565 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012566}
12567
12568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012569RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012570#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012571 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012572 ASSERT(args.length() == 1);
12573 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012574 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012575 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012576 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012577 return Failure::Exception();
12578 }
12579 func->code()->PrintLn();
12580#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012581 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012582}
ager@chromium.org9085a012009-05-11 19:22:57 +000012583
12584
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012585RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012586#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012587 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012588 ASSERT(args.length() == 1);
12589 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012590 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012591 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012592 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012593 return Failure::Exception();
12594 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012595 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012596#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012597 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012598}
12599
12600
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012601RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012602 NoHandleAllocation ha;
12603 ASSERT(args.length() == 1);
12604
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012605 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000012606 return f->shared()->inferred_name();
12607}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012608
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012609
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012610static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12611 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012612 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012613 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012614 int counter = 0;
12615 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012616 for (HeapObject* obj = iterator->next();
12617 obj != NULL;
12618 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012619 ASSERT(obj != NULL);
12620 if (!obj->IsSharedFunctionInfo()) {
12621 continue;
12622 }
12623 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12624 if (shared->script() != script) {
12625 continue;
12626 }
12627 if (counter < buffer_size) {
12628 buffer->set(counter, shared);
12629 }
12630 counter++;
12631 }
12632 return counter;
12633}
12634
12635// For a script finds all SharedFunctionInfo's in the heap that points
12636// to this script. Returns JSArray of SharedFunctionInfo wrapped
12637// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012638RUNTIME_FUNCTION(MaybeObject*,
12639 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012640 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012641 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012642 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012643
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012644
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012645 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12646
12647 const int kBufferSize = 32;
12648
12649 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012650 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012651 int number;
12652 {
12653 isolate->heap()->EnsureHeapIsIterable();
12654 AssertNoAllocation no_allocations;
12655 HeapIterator heap_iterator;
12656 Script* scr = *script;
12657 FixedArray* arr = *array;
12658 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12659 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012660 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012661 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012662 isolate->heap()->EnsureHeapIsIterable();
12663 AssertNoAllocation no_allocations;
12664 HeapIterator heap_iterator;
12665 Script* scr = *script;
12666 FixedArray* arr = *array;
12667 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012668 }
12669
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012670 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012671 result->set_length(Smi::FromInt(number));
12672
12673 LiveEdit::WrapSharedFunctionInfos(result);
12674
12675 return *result;
12676}
12677
12678// For a script calculates compilation information about all its functions.
12679// The script source is explicitly specified by the second argument.
12680// The source of the actual script is not used, however it is important that
12681// all generated code keeps references to this particular instance of script.
12682// Returns a JSArray of compilation infos. The array is ordered so that
12683// each function with all its descendant is always stored in a continues range
12684// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012685RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012686 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012687 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012688 CONVERT_ARG_CHECKED(JSValue, script, 0);
12689 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012690 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12691
12692 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12693
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012694 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012695 return Failure::Exception();
12696 }
12697
12698 return result;
12699}
12700
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012701// Changes the source of the script to a new_source.
12702// If old_script_name is provided (i.e. is a String), also creates a copy of
12703// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012704RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012705 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012706 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012707 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
12708 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012709 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012710
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012711 RUNTIME_ASSERT(original_script_value->value()->IsScript());
12712 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012713
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012714 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12715 new_source,
12716 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012717
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012718 if (old_script->IsScript()) {
12719 Handle<Script> script_handle(Script::cast(old_script));
12720 return *(GetScriptWrapper(script_handle));
12721 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012722 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012723 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012724}
12725
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012727RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012728 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012729 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012730 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012731 return LiveEdit::FunctionSourceUpdated(shared_info);
12732}
12733
12734
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012735// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012736RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012737 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012738 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012739 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
12740 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012741
ager@chromium.orgac091b72010-05-05 07:34:42 +000012742 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012743}
12744
12745// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012746RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012747 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012748 HandleScope scope(isolate);
12749 Handle<Object> function_object(args[0], isolate);
12750 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012751
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012752 if (function_object->IsJSValue()) {
12753 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12754 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012755 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
12756 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012757 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012758 }
12759
12760 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12761 } else {
12762 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12763 // and we check it in this function.
12764 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012765
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012766 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012767}
12768
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012769
12770// In a code of a parent function replaces original function as embedded object
12771// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012772RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012773 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012774 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012775
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012776 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
12777 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
12778 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012779
12780 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12781 subst_wrapper);
12782
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012783 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012784}
12785
12786
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012787// Updates positions of a shared function info (first parameter) according
12788// to script source change. Text change is described in second parameter as
12789// array of groups of 3 numbers:
12790// (change_begin, change_end, change_end_new_position).
12791// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012792RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012793 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012794 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012795 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12796 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012797
ager@chromium.orgac091b72010-05-05 07:34:42 +000012798 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012799}
12800
12801
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012802// For array of SharedFunctionInfo's (each wrapped in JSValue)
12803// checks that none of them have activations on stacks (of any thread).
12804// Returns array of the same length with corresponding results of
12805// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012806RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012807 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012808 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012809 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12810 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012811
ager@chromium.org357bf652010-04-12 11:30:10 +000012812 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012813}
12814
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012815// Compares 2 strings line-by-line, then token-wise and returns diff in form
12816// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12817// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012818RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012819 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012820 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012821 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
12822 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012823
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012824 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012825}
12826
12827
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012828// A testing entry. Returns statement position which is the closest to
12829// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012830RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012831 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012832 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012833 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012834 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12835
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012836 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012837
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012838 if (code->kind() != Code::FUNCTION &&
12839 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012840 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012841 }
12842
12843 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012844 int closest_pc = 0;
12845 int distance = kMaxInt;
12846 while (!it.done()) {
12847 int statement_position = static_cast<int>(it.rinfo()->data());
12848 // Check if this break point is closer that what was previously found.
12849 if (source_position <= statement_position &&
12850 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012851 closest_pc =
12852 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012853 distance = statement_position - source_position;
12854 // Check whether we can't get any closer.
12855 if (distance == 0) break;
12856 }
12857 it.next();
12858 }
12859
12860 return Smi::FromInt(closest_pc);
12861}
12862
12863
ager@chromium.org357bf652010-04-12 11:30:10 +000012864// Calls specified function with or without entering the debugger.
12865// This is used in unit tests to run code as if debugger is entered or simply
12866// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012867RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012868 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012869 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012870 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12871 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000012872
12873 Handle<Object> result;
12874 bool pending_exception;
12875 {
12876 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012877 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012878 &pending_exception);
12879 } else {
12880 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012881 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012882 &pending_exception);
12883 }
12884 }
12885 if (!pending_exception) {
12886 return *result;
12887 } else {
12888 return Failure::Exception();
12889 }
12890}
12891
12892
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012893// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012894RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012895 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012896 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012897 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12898 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012899 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012900}
12901
12902
12903// Performs a GC.
12904// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012905RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012906 isolate->heap()->CollectAllGarbage(true, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012907 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012908}
12909
12910
12911// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012912RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012913 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012914 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012915 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012916 }
12917 return Smi::FromInt(usage);
12918}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012919
12920
12921// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012922RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012923#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012924 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012925#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012926 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012927#endif
12928}
12929
12930
12931// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012932RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012933#ifdef LIVE_OBJECT_LIST
12934 return LiveObjectList::Capture();
12935#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012936 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012937#endif
12938}
12939
12940
12941// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012942RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012943#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012944 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012945 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012946 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012947#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012948 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012949#endif
12950}
12951
12952
12953// Generates the response to a debugger request for a dump of the objects
12954// contained in the difference between the captured live object lists
12955// specified by id1 and id2.
12956// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12957// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012958RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012959#ifdef LIVE_OBJECT_LIST
12960 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012961 CONVERT_SMI_ARG_CHECKED(id1, 0);
12962 CONVERT_SMI_ARG_CHECKED(id2, 1);
12963 CONVERT_SMI_ARG_CHECKED(start, 2);
12964 CONVERT_SMI_ARG_CHECKED(count, 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012965 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012966 EnterDebugger enter_debugger;
12967 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12968#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012969 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012970#endif
12971}
12972
12973
12974// Gets the specified object as requested by the debugger.
12975// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012976RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012977#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012978 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012979 Object* result = LiveObjectList::GetObj(obj_id);
12980 return result;
12981#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012982 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012983#endif
12984}
12985
12986
12987// Gets the obj id for the specified address if valid.
12988// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012989RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012990#ifdef LIVE_OBJECT_LIST
12991 HandleScope scope;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012992 CONVERT_ARG_HANDLE_CHECKED(String, address, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012993 Object* result = LiveObjectList::GetObjId(address);
12994 return result;
12995#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012996 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012997#endif
12998}
12999
13000
13001// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013002RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013003#ifdef LIVE_OBJECT_LIST
13004 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013005 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013006 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
13007 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
13008 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
13009 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013010 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013011
13012 Handle<JSObject> instance_filter;
13013 if (args[1]->IsJSObject()) {
13014 instance_filter = args.at<JSObject>(1);
13015 }
13016 bool verbose = false;
13017 if (args[2]->IsBoolean()) {
13018 verbose = args[2]->IsTrue();
13019 }
13020 int start = 0;
13021 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013022 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013023 }
13024 int limit = Smi::kMaxValue;
13025 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013026 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013027 }
13028
13029 return LiveObjectList::GetObjRetainers(obj_id,
13030 instance_filter,
13031 verbose,
13032 start,
13033 limit,
13034 filter_obj);
13035#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013036 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013037#endif
13038}
13039
13040
13041// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013042RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013043#ifdef LIVE_OBJECT_LIST
13044 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013045 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
13046 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013047 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
13048
13049 Handle<JSObject> instance_filter;
13050 if (args[2]->IsJSObject()) {
13051 instance_filter = args.at<JSObject>(2);
13052 }
13053
13054 Object* result =
13055 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
13056 return result;
13057#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013058 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013059#endif
13060}
13061
13062
13063// Generates the response to a debugger request for a list of all
13064// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013065RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013066#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013067 CONVERT_SMI_ARG_CHECKED(start, 0);
13068 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013069 return LiveObjectList::Info(start, count);
13070#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013071 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013072#endif
13073}
13074
13075
13076// Gets a dump of the specified object as requested by the debugger.
13077// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013078RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013079#ifdef LIVE_OBJECT_LIST
13080 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013081 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013082 Object* result = LiveObjectList::PrintObj(obj_id);
13083 return result;
13084#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013085 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013086#endif
13087}
13088
13089
13090// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013091RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013092#ifdef LIVE_OBJECT_LIST
13093 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013094 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013095#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013096 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013097#endif
13098}
13099
13100
13101// Generates the response to a debugger request for a summary of the types
13102// of objects in the difference between the captured live object lists
13103// specified by id1 and id2.
13104// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13105// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013106RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013107#ifdef LIVE_OBJECT_LIST
13108 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013109 CONVERT_SMI_ARG_CHECKED(id1, 0);
13110 CONVERT_SMI_ARG_CHECKED(id2, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013111 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013112
13113 EnterDebugger enter_debugger;
13114 return LiveObjectList::Summarize(id1, id2, filter_obj);
13115#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013116 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013117#endif
13118}
13119
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013120#endif // ENABLE_DEBUGGER_SUPPORT
13121
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013122
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013123RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013124 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013125 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013126 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013127}
13128
13129
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013130RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013131 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013132 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013133 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013134}
13135
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013136
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013137// Finds the script object from the script data. NOTE: This operation uses
13138// heap traversal to find the function generated for the source position
13139// for the requested break point. For lazily compiled functions several heap
13140// traversals might be required rendering this operation as a rather slow
13141// operation. However for setting break points which is normally done through
13142// some kind of user interaction the performance is not crucial.
13143static Handle<Object> Runtime_GetScriptFromScriptName(
13144 Handle<String> script_name) {
13145 // Scan the heap for Script objects to find the script with the requested
13146 // script data.
13147 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013148 script_name->GetHeap()->EnsureHeapIsIterable();
13149 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013150 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013151 HeapObject* obj = NULL;
13152 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013153 // If a script is found check if it has the script data requested.
13154 if (obj->IsScript()) {
13155 if (Script::cast(obj)->name()->IsString()) {
13156 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13157 script = Handle<Script>(Script::cast(obj));
13158 }
13159 }
13160 }
13161 }
13162
13163 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013164 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013165
13166 // Return the script found.
13167 return GetScriptWrapper(script);
13168}
13169
13170
13171// Get the script object from script data. NOTE: Regarding performance
13172// see the NOTE for GetScriptFromScriptData.
13173// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013174RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013175 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013176
13177 ASSERT(args.length() == 1);
13178
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013179 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013180
13181 // Find the requested script.
13182 Handle<Object> result =
13183 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13184 return *result;
13185}
13186
13187
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013188// Determines whether the given stack frame should be displayed in
13189// a stack trace. The caller is the error constructor that asked
13190// for the stack trace to be collected. The first time a construct
13191// call to this function is encountered it is skipped. The seen_caller
13192// in/out parameter is used to remember if the caller has been seen
13193// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013194static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13195 Object* caller,
13196 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013197 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013198 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013199 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013200 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013201 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13202 Object* raw_fun = frame->function();
13203 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013204 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013205 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013206 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013207 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013208 *seen_caller = true;
13209 return false;
13210 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013211 // Skip all frames until we've seen the caller.
13212 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013213 // Also, skip non-visible built-in functions and any call with the builtins
13214 // object as receiver, so as to not reveal either the builtins object or
13215 // an internal function.
13216 // The --builtins-in-stack-traces command line flag allows including
13217 // internal call sites in the stack trace for debugging purposes.
13218 if (!FLAG_builtins_in_stack_traces) {
13219 JSFunction* fun = JSFunction::cast(raw_fun);
13220 if (frame->receiver()->IsJSBuiltinsObject() ||
13221 (fun->IsBuiltin() && !fun->shared()->native())) {
13222 return false;
13223 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013224 }
13225 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013226}
13227
13228
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013229// Collect the raw data for a stack trace. Returns an array of 4
13230// element segments each containing a receiver, function, code and
13231// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013232RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013233 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013234 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013235 Handle<Object> caller = args.at<Object>(1);
13236 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013237
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013238 HandleScope scope(isolate);
13239 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013240
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013241 limit = Max(limit, 0); // Ensure that limit is not negative.
13242 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013243 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013244 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013245
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013246 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013247 // If the caller parameter is a function we skip frames until we're
13248 // under it before starting to collect.
13249 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013250 int cursor = 0;
13251 int frames_seen = 0;
13252 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013253 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013254 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013255 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013256 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013257 // Set initial size to the maximum inlining level + 1 for the outermost
13258 // function.
13259 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013260 frame->Summarize(&frames);
13261 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013262 if (cursor + 4 > elements->length()) {
13263 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13264 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013265 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013266 for (int i = 0; i < cursor; i++) {
13267 new_elements->set(i, elements->get(i));
13268 }
13269 elements = new_elements;
13270 }
13271 ASSERT(cursor + 4 <= elements->length());
13272
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013273 Handle<Object> recv = frames[i].receiver();
13274 Handle<JSFunction> fun = frames[i].function();
13275 Handle<Code> code = frames[i].code();
13276 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013277 elements->set(cursor++, *recv);
13278 elements->set(cursor++, *fun);
13279 elements->set(cursor++, *code);
13280 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013281 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013282 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013283 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013284 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013285 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013286 // Capture and attach a more detailed stack trace if necessary.
13287 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013288 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013289 return *result;
13290}
13291
13292
ager@chromium.org3811b432009-10-28 14:53:37 +000013293// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013294RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013295 ASSERT_EQ(args.length(), 0);
13296
13297 NoHandleAllocation ha;
13298
13299 const char* version_string = v8::V8::GetVersion();
13300
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013301 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13302 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013303}
13304
13305
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013306RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013307 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013308 OS::PrintError("abort: %s\n",
13309 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013310 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013311 OS::Abort();
13312 UNREACHABLE();
13313 return NULL;
13314}
13315
13316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013317RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013318 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013319 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013320 Object* key = args[1];
13321
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013322 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013323 Object* o = cache->get(finger_index);
13324 if (o == key) {
13325 // The fastest case: hit the same place again.
13326 return cache->get(finger_index + 1);
13327 }
13328
13329 for (int i = finger_index - 2;
13330 i >= JSFunctionResultCache::kEntriesIndex;
13331 i -= 2) {
13332 o = cache->get(i);
13333 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013334 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013335 return cache->get(i + 1);
13336 }
13337 }
13338
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013339 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013340 ASSERT(size <= cache->length());
13341
13342 for (int i = size - 2; i > finger_index; i -= 2) {
13343 o = cache->get(i);
13344 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013345 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013346 return cache->get(i + 1);
13347 }
13348 }
13349
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013350 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013351 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013352
13353 Handle<JSFunctionResultCache> cache_handle(cache);
13354 Handle<Object> key_handle(key);
13355 Handle<Object> value;
13356 {
13357 Handle<JSFunction> factory(JSFunction::cast(
13358 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13359 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013360 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013361 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013362 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013363 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013364 value = Execution::Call(factory,
13365 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013366 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013367 argv,
13368 &pending_exception);
13369 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013370 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013371
13372#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013373 if (FLAG_verify_heap) {
13374 cache_handle->JSFunctionResultCacheVerify();
13375 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013376#endif
13377
13378 // Function invocation may have cleared the cache. Reread all the data.
13379 finger_index = cache_handle->finger_index();
13380 size = cache_handle->size();
13381
13382 // If we have spare room, put new data into it, otherwise evict post finger
13383 // entry which is likely to be the least recently used.
13384 int index = -1;
13385 if (size < cache_handle->length()) {
13386 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13387 index = size;
13388 } else {
13389 index = finger_index + JSFunctionResultCache::kEntrySize;
13390 if (index == cache_handle->length()) {
13391 index = JSFunctionResultCache::kEntriesIndex;
13392 }
13393 }
13394
13395 ASSERT(index % 2 == 0);
13396 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13397 ASSERT(index < cache_handle->length());
13398
13399 cache_handle->set(index, *key_handle);
13400 cache_handle->set(index + 1, *value);
13401 cache_handle->set_finger_index(index);
13402
13403#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013404 if (FLAG_verify_heap) {
13405 cache_handle->JSFunctionResultCacheVerify();
13406 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013407#endif
13408
13409 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013410}
13411
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013412
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013413RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013414 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013415 CONVERT_ARG_HANDLE_CHECKED(String, type, 0);
13416 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013417 return *isolate->factory()->NewJSMessageObject(
13418 type,
13419 arguments,
13420 0,
13421 0,
13422 isolate->factory()->undefined_value(),
13423 isolate->factory()->undefined_value(),
13424 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013425}
13426
13427
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013428RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013429 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013430 return message->type();
13431}
13432
13433
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013434RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013435 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013436 return message->arguments();
13437}
13438
13439
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013440RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013441 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013442 return Smi::FromInt(message->start_position());
13443}
13444
13445
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013446RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013447 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013448 return message->script();
13449}
13450
13451
kasper.lund44510672008-07-25 07:37:58 +000013452#ifdef DEBUG
13453// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13454// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013455RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013456 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013457 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013458#define COUNT_ENTRY(Name, argc, ressize) + 1
13459 int entry_count = 0
13460 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13461 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13462 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13463#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013464 Factory* factory = isolate->factory();
13465 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013466 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013467 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013468#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013469 { \
13470 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013471 Handle<String> name; \
13472 /* Inline runtime functions have an underscore in front of the name. */ \
13473 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013474 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013475 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13476 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013477 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013478 Vector<const char>(#Name, StrLength(#Name))); \
13479 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013480 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013481 pair_elements->set(0, *name); \
13482 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013483 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013484 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013485 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013486 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013487 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013488 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013489 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013490 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013491#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013492 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013493 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013494 return *result;
13495}
kasper.lund44510672008-07-25 07:37:58 +000013496#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013497
13498
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013499RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013500 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013501 CONVERT_ARG_CHECKED(String, format, 0);
13502 CONVERT_ARG_CHECKED(JSArray, elms, 1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013503 String::FlatContent format_content = format->GetFlatContent();
13504 RUNTIME_ASSERT(format_content.IsAscii());
13505 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013506 LOGGER->LogRuntime(chars, elms);
13507 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013508}
13509
13510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013511RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013512 UNREACHABLE(); // implemented as macro in the parser
13513 return NULL;
13514}
13515
13516
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013517#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13518 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013519 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013520 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13521 }
13522
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013523ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013524ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13525ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13526ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13527ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13528ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13529ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13530ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13531ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13532ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13533ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13534ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13535ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13536ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13537
13538#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13539
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013540
13541RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13542 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013543 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
13544 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013545 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13546}
13547
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013548// ----------------------------------------------------------------------------
13549// Implementation of Runtime
13550
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013551#define F(name, number_of_args, result_size) \
13552 { Runtime::k##name, Runtime::RUNTIME, #name, \
13553 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013554
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013555
13556#define I(name, number_of_args, result_size) \
13557 { Runtime::kInline##name, Runtime::INLINE, \
13558 "_" #name, NULL, number_of_args, result_size },
13559
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013560static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013561 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013562 INLINE_FUNCTION_LIST(I)
13563 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013564};
13565
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013566
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013567MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13568 Object* dictionary) {
13569 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013570 ASSERT(dictionary != NULL);
13571 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13572 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013573 Object* name_symbol;
13574 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013575 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013576 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13577 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013578 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013579 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13580 String::cast(name_symbol),
13581 Smi::FromInt(i),
13582 PropertyDetails(NONE, NORMAL));
13583 if (!maybe_dictionary->ToObject(&dictionary)) {
13584 // Non-recoverable failure. Calling code must restart heap
13585 // initialization.
13586 return maybe_dictionary;
13587 }
13588 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013589 }
13590 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013591}
13592
13593
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013594const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13595 Heap* heap = name->GetHeap();
13596 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013597 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013598 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013599 int function_index = Smi::cast(smi_index)->value();
13600 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013601 }
13602 return NULL;
13603}
13604
13605
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013606const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013607 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13608}
13609
13610
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013611void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013612 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013613 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013614 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013615 if (isolate->heap()->new_space()->AddFreshPage()) {
13616 return;
13617 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013618 // Try to do a garbage collection; ignore it if it fails. The C
13619 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013620 isolate->heap()->CollectGarbage(failure->allocation_space(),
13621 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013622 } else {
13623 // Handle last resort GC and make sure to allow future allocations
13624 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013625 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013626 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13627 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013628 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013629}
13630
13631
13632} } // namespace v8::internal