blob: 2bac30473beb0732979c860175535e322cd016dc [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.
72#define CONVERT_CHECKED(Type, name, obj) \
73 RUNTIME_ASSERT(obj->Is##Type()); \
74 Type* name = Type::cast(obj);
75
76#define CONVERT_ARG_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
78 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.
83#define CONVERT_BOOLEAN_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsBoolean()); \
85 bool name = (obj)->IsTrue();
86
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.orgc3b37122011-11-07 10:14:12 +0000109// Assert that the given argument has a valid value for a StrictModeFlag
110// and store it in a StrictModeFlag variable with the given name.
111#define CONVERT_STRICT_MODE_ARG(name, index) \
112 ASSERT(args[index]->IsSmi()); \
113 ASSERT(args.smi_at(index) == kStrictMode || \
114 args.smi_at(index) == kNonStrictMode); \
115 StrictModeFlag name = \
116 static_cast<StrictModeFlag>(args.smi_at(index));
117
118
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000119// Assert that the given argument has a valid value for a LanguageMode
120// and store it in a LanguageMode variable with the given name.
121#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
122 ASSERT(args[index]->IsSmi()); \
123 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
124 args.smi_at(index) == STRICT_MODE || \
125 args.smi_at(index) == EXTENDED_MODE); \
126 LanguageMode name = \
127 static_cast<LanguageMode>(args.smi_at(index));
128
129
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000130MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
131 JSObject* boilerplate) {
132 StackLimitCheck check(isolate);
133 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000134
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000135 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000136 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000137 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000138 if (!maybe_result->ToObject(&result)) return maybe_result;
139 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000140 JSObject* copy = JSObject::cast(result);
141
142 // Deep copy local properties.
143 if (copy->HasFastProperties()) {
144 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000145 for (int i = 0; i < properties->length(); i++) {
146 Object* value = properties->get(i);
147 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000149 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000150 if (!maybe_result->ToObject(&result)) return maybe_result;
151 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 }
154 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000155 int nof = copy->map()->inobject_properties();
156 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 Object* value = copy->InObjectPropertyAt(i);
158 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000159 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000163 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000164 }
165 }
166 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000167 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000168 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000171 FixedArray* names = FixedArray::cast(result);
172 copy->GetLocalPropertyNames(names, 0);
173 for (int i = 0; i < names->length(); i++) {
174 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000175 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000176 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000177 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000178 // Only deep copy fields from the object literal expression.
179 // In particular, don't try to copy the length attribute of
180 // an array.
181 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000182 Object* value =
183 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000184 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000185 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000186 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000187 if (!maybe_result->ToObject(&result)) return maybe_result;
188 }
189 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000190 // Creating object copy for literals. No strict mode needed.
191 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000192 if (!maybe_result->ToObject(&result)) return maybe_result;
193 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000194 }
195 }
196 }
197
198 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000199 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000200 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000202 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000203 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000204 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000205 if (elements->map() == heap->fixed_cow_array_map()) {
206 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000207#ifdef DEBUG
208 for (int i = 0; i < elements->length(); i++) {
209 ASSERT(!elements->get(i)->IsJSObject());
210 }
211#endif
212 } else {
213 for (int i = 0; i < elements->length(); i++) {
214 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000215 ASSERT(value->IsSmi() ||
216 value->IsTheHole() ||
217 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000218 if (value->IsJSObject()) {
219 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000220 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
221 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000222 if (!maybe_result->ToObject(&result)) return maybe_result;
223 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000224 elements->set(i, result);
225 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000226 }
227 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000228 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000229 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000230 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000231 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000232 int capacity = element_dictionary->Capacity();
233 for (int i = 0; i < capacity; i++) {
234 Object* k = element_dictionary->KeyAt(i);
235 if (element_dictionary->IsKey(k)) {
236 Object* value = element_dictionary->ValueAt(i);
237 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000238 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000239 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
240 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000241 if (!maybe_result->ToObject(&result)) return maybe_result;
242 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000243 element_dictionary->ValueAtPut(i, result);
244 }
245 }
246 }
247 break;
248 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000249 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000250 UNIMPLEMENTED();
251 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000252 case EXTERNAL_PIXEL_ELEMENTS:
253 case EXTERNAL_BYTE_ELEMENTS:
254 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
255 case EXTERNAL_SHORT_ELEMENTS:
256 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
257 case EXTERNAL_INT_ELEMENTS:
258 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
259 case EXTERNAL_FLOAT_ELEMENTS:
260 case EXTERNAL_DOUBLE_ELEMENTS:
261 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000262 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000263 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000264 }
265 return copy;
266}
267
268
ager@chromium.org236ad962008-09-25 09:45:57 +0000269static Handle<Map> ComputeObjectLiteralMap(
270 Handle<Context> context,
271 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000272 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000273 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000274 int properties_length = constant_properties->length();
275 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000276 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000277 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000278 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000279 for (int p = 0; p != properties_length; p += 2) {
280 Object* key = constant_properties->get(p);
281 uint32_t element_index = 0;
282 if (key->IsSymbol()) {
283 number_of_symbol_keys++;
284 } else if (key->ToArrayIndex(&element_index)) {
285 // An index key does not require space in the property backing store.
286 number_of_properties--;
287 } else {
288 // Bail out as a non-symbol non-index key makes caching impossible.
289 // ASSERT to make sure that the if condition after the loop is false.
290 ASSERT(number_of_symbol_keys != number_of_properties);
291 break;
292 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000293 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000294 // If we only have symbols and array indices among keys then we can
295 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000296 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000297 if ((number_of_symbol_keys == number_of_properties) &&
298 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000300 Handle<FixedArray> keys =
301 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000302 if (number_of_symbol_keys > 0) {
303 int index = 0;
304 for (int p = 0; p < properties_length; p += 2) {
305 Object* key = constant_properties->get(p);
306 if (key->IsSymbol()) {
307 keys->set(index++, key);
308 }
309 }
310 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000311 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000312 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000313 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000314 }
315 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000316 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000317 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000318 Handle<Map>(context->object_function()->initial_map()),
319 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000320}
321
322
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000323static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000325 Handle<FixedArray> literals,
326 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000327
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000328
329static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000331 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000332 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000333 bool should_have_fast_elements,
334 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000335 // Get the global context from the literals array. This is the
336 // context in which the function was created and we use the object
337 // function from this context to create the object literal. We do
338 // not use the object function from the current global context
339 // because this might be the object function from another context
340 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000341 Handle<Context> context =
342 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000344 // In case we have function literals, we want the object to be in
345 // slow properties mode for now. We don't go in the map cache because
346 // maps with constant functions can't be shared if the functions are
347 // not the same (which is the common case).
348 bool is_result_from_cache = false;
349 Handle<Map> map = has_function_literal
350 ? Handle<Map>(context->object_function()->initial_map())
351 : ComputeObjectLiteralMap(context,
352 constant_properties,
353 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000355 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000356
357 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000358 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000359
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000360 // Add the constant properties to the boilerplate.
361 int length = constant_properties->length();
362 bool should_transform =
363 !is_result_from_cache && boilerplate->HasFastProperties();
364 if (should_transform || has_function_literal) {
365 // Normalize the properties of object to avoid n^2 behavior
366 // when extending the object multiple properties. Indicate the number of
367 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000368 JSObject::NormalizeProperties(
369 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000370 }
371
372 for (int index = 0; index < length; index +=2) {
373 Handle<Object> key(constant_properties->get(index+0), isolate);
374 Handle<Object> value(constant_properties->get(index+1), isolate);
375 if (value->IsFixedArray()) {
376 // The value contains the constant_properties of a
377 // simple object or array literal.
378 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
379 value = CreateLiteralBoilerplate(isolate, literals, array);
380 if (value.is_null()) return value;
381 }
382 Handle<Object> result;
383 uint32_t element_index = 0;
384 if (key->IsSymbol()) {
385 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
386 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000387 result = JSObject::SetOwnElement(
388 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000389 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000390 Handle<String> name(String::cast(*key));
391 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000392 result = JSObject::SetLocalPropertyIgnoreAttributes(
393 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000394 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000395 } else if (key->ToArrayIndex(&element_index)) {
396 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000397 result = JSObject::SetOwnElement(
398 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000399 } else {
400 // Non-uint32 number.
401 ASSERT(key->IsNumber());
402 double num = key->Number();
403 char arr[100];
404 Vector<char> buffer(arr, ARRAY_SIZE(arr));
405 const char* str = DoubleToCString(num, buffer);
406 Handle<String> name =
407 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000408 result = JSObject::SetLocalPropertyIgnoreAttributes(
409 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000411 // If setting the property on the boilerplate throws an
412 // exception, the exception is converted to an empty handle in
413 // the handle based operations. In that case, we need to
414 // convert back to an exception.
415 if (result.is_null()) return result;
416 }
417
418 // Transform to fast properties if necessary. For object literals with
419 // containing function literals we defer this operation until after all
420 // computed properties have been assigned so that we can generate
421 // constant function properties.
422 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000423 JSObject::TransformToFastProperties(
424 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000425 }
426
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000427 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000428}
429
430
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000431static const int kSmiOnlyLiteralMinimumLength = 1024;
432
433
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000434Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000436 Handle<FixedArray> literals,
437 Handle<FixedArray> elements) {
438 // Create the JSArray.
439 Handle<JSFunction> constructor(
440 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000441 Handle<JSArray> object =
442 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000443
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000444 ElementsKind constant_elements_kind =
445 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
446 Handle<FixedArrayBase> constant_elements_values(
447 FixedArrayBase::cast(elements->get(1)));
448
449 ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
450 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
451 bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
452 constant_elements_kind > object->GetElementsKind();
453
454 if (!FLAG_smi_only_arrays &&
455 constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
456 constant_elements_kind != object->GetElementsKind()) {
457 allow_literal_kind_transition = true;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000458 }
459
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000460 // If the ElementsKind of the constant values of the array literal are less
461 // specific than the ElementsKind of the boilerplate array object, change the
462 // boilerplate array object's map to reflect that kind.
463 if (allow_literal_kind_transition) {
464 Handle<Map> transitioned_array_map =
465 isolate->factory()->GetElementsTransitionMap(object,
466 constant_elements_kind);
467 object->set_map(*transitioned_array_map);
468 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000469
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000470 Handle<FixedArrayBase> copied_elements_values;
471 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
472 ASSERT(FLAG_smi_only_arrays);
473 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
474 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000475 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000476 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
477 constant_elements_kind == FAST_ELEMENTS);
478 const bool is_cow =
479 (constant_elements_values->map() ==
480 isolate->heap()->fixed_cow_array_map());
481 if (is_cow) {
482 copied_elements_values = constant_elements_values;
483#if DEBUG
484 Handle<FixedArray> fixed_array_values =
485 Handle<FixedArray>::cast(copied_elements_values);
486 for (int i = 0; i < fixed_array_values->length(); i++) {
487 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
488 }
489#endif
490 } else {
491 Handle<FixedArray> fixed_array_values =
492 Handle<FixedArray>::cast(constant_elements_values);
493 Handle<FixedArray> fixed_array_values_copy =
494 isolate->factory()->CopyFixedArray(fixed_array_values);
495 copied_elements_values = fixed_array_values_copy;
496 for (int i = 0; i < fixed_array_values->length(); i++) {
497 Object* current = fixed_array_values->get(i);
498 if (current->IsFixedArray()) {
499 // The value contains the constant_properties of a
500 // simple object or array literal.
501 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
502 Handle<Object> result =
503 CreateLiteralBoilerplate(isolate, literals, fa);
504 if (result.is_null()) return result;
505 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000506 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000507 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000508 }
509 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000510 object->set_elements(*copied_elements_values);
511 object->set_length(Smi::FromInt(copied_elements_values->length()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000512 return object;
513}
514
515
516static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000517 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000518 Handle<FixedArray> literals,
519 Handle<FixedArray> array) {
520 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000522 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000523 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000524 return CreateObjectLiteralBoilerplate(isolate,
525 literals,
526 elements,
527 true,
528 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000529 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000530 return CreateObjectLiteralBoilerplate(isolate,
531 literals,
532 elements,
533 false,
534 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000535 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000536 return Runtime::CreateArrayLiteralBoilerplate(
537 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000538 default:
539 UNREACHABLE();
540 return Handle<Object>::null();
541 }
542}
543
544
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000545RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000547 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000548 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000549 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000550 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000551 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000552 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
553 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000554
555 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000556 Handle<Object> boilerplate(literals->get(literals_index), isolate);
557 if (*boilerplate == isolate->heap()->undefined_value()) {
558 boilerplate = CreateObjectLiteralBoilerplate(isolate,
559 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000560 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000561 should_have_fast_elements,
562 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000563 if (boilerplate.is_null()) return Failure::Exception();
564 // Update the functions literal and return the boilerplate.
565 literals->set(literals_index, *boilerplate);
566 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000567 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000568}
569
570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000571RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000572 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000573 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000574 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000575 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000577 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
579 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580
581 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000582 Handle<Object> boilerplate(literals->get(literals_index), isolate);
583 if (*boilerplate == isolate->heap()->undefined_value()) {
584 boilerplate = CreateObjectLiteralBoilerplate(isolate,
585 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000586 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000587 should_have_fast_elements,
588 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589 if (boilerplate.is_null()) return Failure::Exception();
590 // Update the functions literal and return the boilerplate.
591 literals->set(literals_index, *boilerplate);
592 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000593 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000594}
595
596
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000597RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000598 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000599 ASSERT(args.length() == 3);
600 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000601 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
603
604 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000605 Handle<Object> boilerplate(literals->get(literals_index), isolate);
606 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000607 boilerplate =
608 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000609 if (boilerplate.is_null()) return Failure::Exception();
610 // Update the functions literal and return the boilerplate.
611 literals->set(literals_index, *boilerplate);
612 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000613 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000614}
615
616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000617RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000619 ASSERT(args.length() == 3);
620 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000621 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000622 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
623
624 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000625 Handle<Object> boilerplate(literals->get(literals_index), isolate);
626 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000627 ASSERT(*elements != isolate->heap()->empty_fixed_array());
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 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000634 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000635 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000636 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000637 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000638 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000639}
640
641
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000642RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
643 ASSERT(args.length() == 2);
644 Object* handler = args[0];
645 Object* prototype = args[1];
646 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000647 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000648 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
649}
650
651
lrn@chromium.org34e60782011-09-15 07:25:40 +0000652RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
653 ASSERT(args.length() == 4);
654 Object* handler = args[0];
655 Object* call_trap = args[1];
656 Object* construct_trap = args[2];
657 Object* prototype = args[3];
658 Object* used_prototype =
659 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
660 return isolate->heap()->AllocateJSFunctionProxy(
661 handler, call_trap, construct_trap, used_prototype);
662}
663
664
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000665RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
666 ASSERT(args.length() == 1);
667 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000668 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669}
670
671
lrn@chromium.org34e60782011-09-15 07:25:40 +0000672RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
673 ASSERT(args.length() == 1);
674 Object* obj = args[0];
675 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
676}
677
678
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000679RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
680 ASSERT(args.length() == 1);
681 CONVERT_CHECKED(JSProxy, proxy, args[0]);
682 return proxy->handler();
683}
684
685
lrn@chromium.org34e60782011-09-15 07:25:40 +0000686RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
687 ASSERT(args.length() == 1);
688 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
689 return proxy->call_trap();
690}
691
692
693RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
694 ASSERT(args.length() == 1);
695 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
696 return proxy->construct_trap();
697}
698
699
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000700RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
701 ASSERT(args.length() == 1);
702 CONVERT_CHECKED(JSProxy, proxy, args[0]);
703 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000704 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000705}
706
707
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
709 HandleScope scope(isolate);
710 ASSERT(args.length() == 1);
711 CONVERT_ARG_CHECKED(JSSet, holder, 0);
712 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
713 holder->set_table(*table);
714 return *holder;
715}
716
717
718RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
719 HandleScope scope(isolate);
720 ASSERT(args.length() == 2);
721 CONVERT_ARG_CHECKED(JSSet, holder, 0);
722 Handle<Object> key(args[1]);
723 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
724 table = ObjectHashSetAdd(table, key);
725 holder->set_table(*table);
726 return isolate->heap()->undefined_symbol();
727}
728
729
730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 2);
733 CONVERT_ARG_CHECKED(JSSet, holder, 0);
734 Handle<Object> key(args[1]);
735 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
736 return isolate->heap()->ToBoolean(table->Contains(*key));
737}
738
739
740RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
741 HandleScope scope(isolate);
742 ASSERT(args.length() == 2);
743 CONVERT_ARG_CHECKED(JSSet, holder, 0);
744 Handle<Object> key(args[1]);
745 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
746 table = ObjectHashSetRemove(table, key);
747 holder->set_table(*table);
748 return isolate->heap()->undefined_symbol();
749}
750
751
752RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 1);
755 CONVERT_ARG_CHECKED(JSMap, holder, 0);
756 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
757 holder->set_table(*table);
758 return *holder;
759}
760
761
762RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
763 HandleScope scope(isolate);
764 ASSERT(args.length() == 2);
765 CONVERT_ARG_CHECKED(JSMap, holder, 0);
766 Handle<Object> key(args[1]);
767 return ObjectHashTable::cast(holder->table())->Lookup(*key);
768}
769
770
771RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
772 HandleScope scope(isolate);
773 ASSERT(args.length() == 3);
774 CONVERT_ARG_CHECKED(JSMap, holder, 0);
775 Handle<Object> key(args[1]);
776 Handle<Object> value(args[2]);
777 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
778 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
779 holder->set_table(*new_table);
780 return *value;
781}
782
783
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000784RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 1);
787 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
788 ASSERT(weakmap->map()->inobject_properties() == 0);
789 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
790 weakmap->set_table(*table);
791 weakmap->set_next(Smi::FromInt(0));
792 return *weakmap;
793}
794
795
796RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
797 NoHandleAllocation ha;
798 ASSERT(args.length() == 2);
799 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000800 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
801 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000802}
803
804
805RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
806 HandleScope scope(isolate);
807 ASSERT(args.length() == 3);
808 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000809 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000810 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000811 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000812 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
813 weakmap->set_table(*new_table);
814 return *value;
815}
816
817
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000818RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000819 NoHandleAllocation ha;
820 ASSERT(args.length() == 1);
821 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000822 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000823 return JSObject::cast(obj)->class_name();
824}
825
ager@chromium.org7c537e22008-10-16 08:43:32 +0000826
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000827RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
828 NoHandleAllocation ha;
829 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000830 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
831 Object* obj = input_obj;
832 // We don't expect access checks to be needed on JSProxy objects.
833 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000834 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000835 if (obj->IsAccessCheckNeeded() &&
836 !isolate->MayNamedAccess(JSObject::cast(obj),
837 isolate->heap()->Proto_symbol(),
838 v8::ACCESS_GET)) {
839 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
840 return isolate->heap()->undefined_value();
841 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000842 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000843 } while (obj->IsJSObject() &&
844 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000845 return obj;
846}
847
848
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000849RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000850 NoHandleAllocation ha;
851 ASSERT(args.length() == 2);
852 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
853 Object* O = args[0];
854 Object* V = args[1];
855 while (true) {
856 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000857 if (prototype->IsNull()) return isolate->heap()->false_value();
858 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000859 V = prototype;
860 }
861}
862
863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000864RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000865 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000866 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000867 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000868 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000869}
870
871
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000872// Recursively traverses hidden prototypes if property is not found
873static void GetOwnPropertyImplementation(JSObject* obj,
874 String* name,
875 LookupResult* result) {
876 obj->LocalLookupRealNamedProperty(name, result);
877
878 if (!result->IsProperty()) {
879 Object* proto = obj->GetPrototype();
880 if (proto->IsJSObject() &&
881 JSObject::cast(proto)->map()->is_hidden_prototype())
882 GetOwnPropertyImplementation(JSObject::cast(proto),
883 name, result);
884 }
885}
886
887
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000888static bool CheckAccessException(LookupResult* result,
889 v8::AccessType access_type) {
890 if (result->type() == CALLBACKS) {
891 Object* callback = result->GetCallbackObject();
892 if (callback->IsAccessorInfo()) {
893 AccessorInfo* info = AccessorInfo::cast(callback);
894 bool can_access =
895 (access_type == v8::ACCESS_HAS &&
896 (info->all_can_read() || info->all_can_write())) ||
897 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
898 (access_type == v8::ACCESS_SET && info->all_can_write());
899 return can_access;
900 }
901 }
902
903 return false;
904}
905
906
907static bool CheckAccess(JSObject* obj,
908 String* name,
909 LookupResult* result,
910 v8::AccessType access_type) {
911 ASSERT(result->IsProperty());
912
913 JSObject* holder = result->holder();
914 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000915 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000916 while (true) {
917 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000918 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000919 // Access check callback denied the access, but some properties
920 // can have a special permissions which override callbacks descision
921 // (currently see v8::AccessControl).
922 break;
923 }
924
925 if (current == holder) {
926 return true;
927 }
928
929 current = JSObject::cast(current->GetPrototype());
930 }
931
932 // API callbacks can have per callback access exceptions.
933 switch (result->type()) {
934 case CALLBACKS: {
935 if (CheckAccessException(result, access_type)) {
936 return true;
937 }
938 break;
939 }
940 case INTERCEPTOR: {
941 // If the object has an interceptor, try real named properties.
942 // Overwrite the result to fetch the correct property later.
943 holder->LookupRealNamedProperty(name, result);
944 if (result->IsProperty()) {
945 if (CheckAccessException(result, access_type)) {
946 return true;
947 }
948 }
949 break;
950 }
951 default:
952 break;
953 }
954
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000955 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000956 return false;
957}
958
959
960// TODO(1095): we should traverse hidden prototype hierachy as well.
961static bool CheckElementAccess(JSObject* obj,
962 uint32_t index,
963 v8::AccessType access_type) {
964 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000965 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000966 return false;
967 }
968
969 return true;
970}
971
972
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000973// Enumerator used as indices into the array returned from GetOwnProperty
974enum PropertyDescriptorIndices {
975 IS_ACCESSOR_INDEX,
976 VALUE_INDEX,
977 GETTER_INDEX,
978 SETTER_INDEX,
979 WRITABLE_INDEX,
980 ENUMERABLE_INDEX,
981 CONFIGURABLE_INDEX,
982 DESCRIPTOR_SIZE
983};
984
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000985// Returns an array with the property description:
986// if args[1] is not a property on args[0]
987// returns undefined
988// if args[1] is a data property on args[0]
989// [false, value, Writeable, Enumerable, Configurable]
990// if args[1] is an accessor on args[0]
991// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000992RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000993 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000994 Heap* heap = isolate->heap();
995 HandleScope scope(isolate);
996 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
997 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000998 LookupResult result(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000999 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1000 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001001
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001002 // This could be an element.
1003 uint32_t index;
1004 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001005 switch (obj->HasLocalElement(index)) {
1006 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001007 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001008
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001009 case JSObject::STRING_CHARACTER_ELEMENT: {
1010 // Special handling of string objects according to ECMAScript 5
1011 // 15.5.5.2. Note that this might be a string object with elements
1012 // other than the actual string value. This is covered by the
1013 // subsequent cases.
1014 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1015 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001016 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001018 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001019 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001020 elms->set(WRITABLE_INDEX, heap->false_value());
1021 elms->set(ENUMERABLE_INDEX, heap->false_value());
1022 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001023 return *desc;
1024 }
1025
1026 case JSObject::INTERCEPTED_ELEMENT:
1027 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001028 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001029 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001030 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001031 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001032 elms->set(WRITABLE_INDEX, heap->true_value());
1033 elms->set(ENUMERABLE_INDEX, heap->true_value());
1034 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001035 return *desc;
1036 }
1037
1038 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001039 Handle<JSObject> holder = obj;
1040 if (obj->IsJSGlobalProxy()) {
1041 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001042 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001043 ASSERT(proto->IsJSGlobalObject());
1044 holder = Handle<JSObject>(JSObject::cast(proto));
1045 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001046 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001047 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001048 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001049 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001050 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001051 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001052 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001053 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001054 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001055 PropertyDetails details = dictionary->DetailsAt(entry);
1056 switch (details.type()) {
1057 case CALLBACKS: {
1058 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001059 AccessorPair* accessors =
1060 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001061 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001062 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001063 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001064 }
1065 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001066 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001067 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001068 break;
1069 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001070 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001071 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001072 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001073 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001074 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001075 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001076 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001077 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001078 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001079 default:
1080 UNREACHABLE();
1081 break;
1082 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001083 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1084 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001085 return *desc;
1086 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001087 }
1088 }
1089
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001090 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001091 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001092
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001093 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001094 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001095 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001096
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001097 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001098 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001099 }
1100
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001101 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1102 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001103
1104 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001105 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001106
1107 if (is_js_accessor) {
1108 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001109 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001110
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001111 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001112 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001113 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001114 }
1115 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001116 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001117 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001118 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001119 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1120 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001121
1122 PropertyAttributes attrs;
1123 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001124 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001125 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1126 if (!maybe_value->ToObject(&value)) return maybe_value;
1127 }
1128 elms->set(VALUE_INDEX, value);
1129 }
1130
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001131 return *desc;
1132}
1133
1134
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001135RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001136 ASSERT(args.length() == 1);
1137 CONVERT_CHECKED(JSObject, obj, args[0]);
1138 return obj->PreventExtensions();
1139}
1140
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001141
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001142RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001143 ASSERT(args.length() == 1);
1144 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001145 if (obj->IsJSGlobalProxy()) {
1146 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001147 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001148 ASSERT(proto->IsJSGlobalObject());
1149 obj = JSObject::cast(proto);
1150 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001151 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001152}
1153
1154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001155RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001156 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001157 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001158 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1159 CONVERT_ARG_CHECKED(String, pattern, 1);
1160 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001161 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1162 if (result.is_null()) return Failure::Exception();
1163 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001164}
1165
1166
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001167RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001168 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001169 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001170 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001171 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172}
1173
1174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001175RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176 ASSERT(args.length() == 1);
1177 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001178 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001179 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001180}
1181
1182
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001183RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184 ASSERT(args.length() == 2);
1185 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001186 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001187 int index = field->value();
1188 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1189 InstanceType type = templ->map()->instance_type();
1190 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1191 type == OBJECT_TEMPLATE_INFO_TYPE);
1192 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001193 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001194 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1195 } else {
1196 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1197 }
1198 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001199}
1200
1201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001202RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001203 ASSERT(args.length() == 1);
1204 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001205 Map* old_map = object->map();
1206 bool needs_access_checks = old_map->is_access_check_needed();
1207 if (needs_access_checks) {
1208 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001209 Object* new_map;
1210 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1211 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1212 }
ager@chromium.org32912102009-01-16 10:38:43 +00001213
1214 Map::cast(new_map)->set_is_access_check_needed(false);
1215 object->set_map(Map::cast(new_map));
1216 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001217 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001218}
1219
1220
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001221RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001222 ASSERT(args.length() == 1);
1223 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001224 Map* old_map = object->map();
1225 if (!old_map->is_access_check_needed()) {
1226 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001227 Object* new_map;
1228 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1229 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1230 }
ager@chromium.org32912102009-01-16 10:38:43 +00001231
1232 Map::cast(new_map)->set_is_access_check_needed(true);
1233 object->set_map(Map::cast(new_map));
1234 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001235 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001236}
1237
1238
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001239static Failure* ThrowRedeclarationError(Isolate* isolate,
1240 const char* type,
1241 Handle<String> name) {
1242 HandleScope scope(isolate);
1243 Handle<Object> type_handle =
1244 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245 Handle<Object> args[2] = { type_handle, name };
1246 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001247 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1248 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249}
1250
1251
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001252RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001253 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001254 HandleScope scope(isolate);
1255 Handle<GlobalObject> global = Handle<GlobalObject>(
1256 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257
ager@chromium.org3811b432009-10-28 14:53:37 +00001258 Handle<Context> context = args.at<Context>(0);
1259 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001260 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001262 // Traverse the name/value pairs and set the properties.
1263 int length = pairs->length();
1264 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001265 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268
1269 // We have to declare a global const property. To capture we only
1270 // assign to it when evaluating the assignment for "const x =
1271 // <expr>" the initial value is the hole.
1272 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274 if (value->IsUndefined() || is_const_property) {
1275 // Lookup the property in the global object, and don't set the
1276 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001277 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 global->Lookup(*name, &lookup);
1279 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001280 // We found an existing property. Unless it was an interceptor
1281 // that claims the property is absent, skip this declaration.
1282 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283 continue;
1284 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001285 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1286 if (attributes != ABSENT) {
1287 continue;
1288 }
1289 // Fall-through and introduce the absent property by using
1290 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001291 }
1292 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001293 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001295 Handle<SharedFunctionInfo> shared =
1296 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001297 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001298 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1299 context,
1300 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001301 value = function;
1302 }
1303
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001304 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 global->LocalLookup(*name, &lookup);
1306
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001307 // Compute the property attributes. According to ECMA-262, section
1308 // 13, page 71, the property must be read-only and
1309 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1310 // property as read-only, so we don't either.
1311 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001312 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001313 attr |= DONT_DELETE;
1314 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001315 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001316 if (is_const_property || (is_native && is_function_declaration)) {
1317 attr |= READ_ONLY;
1318 }
1319
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001320 // Safari does not allow the invocation of callback setters for
1321 // function declarations. To mimic this behavior, we do not allow
1322 // the invocation of setters for function values. This makes a
1323 // difference for global functions with the same names as event
1324 // handlers such as "function onload() {}". Firefox does call the
1325 // onload setter in those case and Safari does not. We follow
1326 // Safari for compatibility.
1327 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001328 // Do not change DONT_DELETE to false from true.
1329 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001330 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001331 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001332 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1333
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001334 RETURN_IF_EMPTY_HANDLE(
1335 isolate,
1336 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1337 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001339 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1340 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1341 ? kNonStrictMode : kStrictMode;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001342 RETURN_IF_EMPTY_HANDLE(
1343 isolate,
1344 JSReceiver::SetProperty(global, name, value,
1345 static_cast<PropertyAttributes>(attr),
1346 strict_mode_flag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347 }
1348 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001349
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001350 ASSERT(!isolate->has_pending_exception());
1351 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001352}
1353
1354
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001355RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001356 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001357 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001359 // Declarations are always made in a function or global context. In the
1360 // case of eval code, the context passed is the context of the caller,
1361 // which may be some nested context and not the declaration context.
1362 RUNTIME_ASSERT(args[0]->IsContext());
1363 Handle<Context> context(Context::cast(args[0])->declaration_context());
1364
ager@chromium.org7c537e22008-10-16 08:43:32 +00001365 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001366 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001367 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001368 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370 int index;
1371 PropertyAttributes attributes;
1372 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001373 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001374 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001375 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376
1377 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001378 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001379 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1380 // Functions are not read-only.
1381 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1382 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001383 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001384 }
1385
1386 // Initialize it if necessary.
1387 if (*initial_value != NULL) {
1388 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001389 ASSERT(holder.is_identical_to(context));
1390 if (((attributes & READ_ONLY) == 0) ||
1391 context->get(index)->IsTheHole()) {
1392 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393 }
1394 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001395 // Slow case: The property is in the context extension object of a
1396 // function context or the global object of a global context.
1397 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001398 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001399 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001400 JSReceiver::SetProperty(object, name, initial_value, mode,
1401 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402 }
1403 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001405 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001406 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001407 // "declared" in the function context's extension context or as a
1408 // property of the the global object.
1409 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001410 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001411 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001412 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001413 // Context extension objects are allocated lazily.
1414 ASSERT(context->IsFunctionContext());
1415 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001416 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001417 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001418 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001419 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420
ager@chromium.org7c537e22008-10-16 08:43:32 +00001421 // Declare the property by setting it to the initial value if provided,
1422 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1423 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001425 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001426 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001427 // Declaring a const context slot is a conflicting declaration if
1428 // there is a callback with that name in a prototype. It is
1429 // allowed to introduce const variables in
1430 // JSContextExtensionObjects. They are treated specially in
1431 // SetProperty and no setters are invoked for those since they are
1432 // not real JSObjects.
1433 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001434 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001435 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001436 object->Lookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001437 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001438 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001439 }
1440 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001441 RETURN_IF_EMPTY_HANDLE(
1442 isolate,
1443 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001444 }
1445
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001446 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001447}
1448
1449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001450RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001451 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001452 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001453 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001454 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001455
1456 // Determine if we need to assign to the variable if it already
1457 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001458 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1459 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
1461 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001462 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001463 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001464 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1465 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1466 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467
1468 // According to ECMA-262, section 12.2, page 62, the property must
1469 // not be deletable.
1470 PropertyAttributes attributes = DONT_DELETE;
1471
1472 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001473 // there, there is a property with this name in the prototype chain.
1474 // We follow Safari and Firefox behavior and only set the property
1475 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001476 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001477 // Note that objects can have hidden prototypes, so we need to traverse
1478 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001479 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001480 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001481 while (object->IsJSObject() &&
1482 JSObject::cast(object)->map()->is_hidden_prototype()) {
1483 JSObject* raw_holder = JSObject::cast(object);
1484 raw_holder->LocalLookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001485 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001486 HandleScope handle_scope(isolate);
1487 Handle<JSObject> holder(raw_holder);
1488 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1489 // Update the raw pointer in case it's changed due to GC.
1490 raw_holder = *holder;
1491 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1492 // Found an interceptor that's not read only.
1493 if (assign) {
1494 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001495 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001496 } else {
1497 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001498 }
1499 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001500 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 }
1503
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001504 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001505 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001506 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001507 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001508 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001509 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510}
1511
1512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001513RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514 // All constants are declared with an initial value. The name
1515 // of the constant is the first argument and the initial value
1516 // is the second.
1517 RUNTIME_ASSERT(args.length() == 2);
1518 CONVERT_ARG_CHECKED(String, name, 0);
1519 Handle<Object> value = args.at<Object>(1);
1520
1521 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001522 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001523
1524 // According to ECMA-262, section 12.2, page 62, the property must
1525 // not be deletable. Since it's a const, it must be READ_ONLY too.
1526 PropertyAttributes attributes =
1527 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1528
1529 // Lookup the property locally in the global object. If it isn't
1530 // there, we add the property and take special precautions to always
1531 // add it as a local property even in case of callbacks in the
1532 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001533 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001534 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 global->LocalLookup(*name, &lookup);
1536 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001537 return global->SetLocalPropertyIgnoreAttributes(*name,
1538 *value,
1539 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540 }
1541
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001544 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001545 HandleScope handle_scope(isolate);
1546 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001547
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001548 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001549 // property through an interceptor and only do it if it's
1550 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001551 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001552 RETURN_IF_EMPTY_HANDLE(
1553 isolate,
1554 JSReceiver::SetProperty(global, name, value, attributes,
1555 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556 return *value;
1557 }
1558
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001559 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 // constant. For now, we determine this by checking if the
1561 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001562 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563 PropertyType type = lookup.type();
1564 if (type == FIELD) {
1565 FixedArray* properties = global->properties();
1566 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001567 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 properties->set(index, *value);
1569 }
1570 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001571 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1572 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001573 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 }
1575 } else {
1576 // Ignore re-initialization of constants that have already been
1577 // assigned a function value.
1578 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1579 }
1580
1581 // Use the set value as the result of the operation.
1582 return *value;
1583}
1584
1585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001586RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001587 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588 ASSERT(args.length() == 3);
1589
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001590 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001591 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001592
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001593 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001594 RUNTIME_ASSERT(args[1]->IsContext());
1595 Handle<Context> context(Context::cast(args[1])->declaration_context());
1596
1597 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598
1599 int index;
1600 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001601 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001602 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001603 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001604 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001606 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001607 ASSERT(holder->IsContext());
1608 // Property was found in a context. Perform the assignment if we
1609 // found some non-constant or an uninitialized constant.
1610 Handle<Context> context = Handle<Context>::cast(holder);
1611 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1612 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613 }
1614 return *value;
1615 }
1616
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001617 // The property could not be found, we introduce it as a property of the
1618 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001619 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001620 Handle<JSObject> global = Handle<JSObject>(
1621 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001622 // Strict mode not needed (const disallowed in strict mode).
1623 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001624 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001625 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001626 return *value;
1627 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001628
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001629 // The property was present in some function's context extension object,
1630 // as a property on the subject of a with, or as a property of the global
1631 // object.
1632 //
1633 // In most situations, eval-introduced consts should still be present in
1634 // the context extension object. However, because declaration and
1635 // initialization are separate, the property might have been deleted
1636 // before we reach the initialization point.
1637 //
1638 // Example:
1639 //
1640 // function f() { eval("delete x; const x;"); }
1641 //
1642 // In that case, the initialization behaves like a normal assignment.
1643 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001644
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001645 if (*object == context->extension()) {
1646 // This is the property that was introduced by the const declaration.
1647 // Set it if it hasn't been set before. NOTE: We cannot use
1648 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001649 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001650 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001651 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001652 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1653
1654 PropertyType type = lookup.type();
1655 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001656 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001657 int index = lookup.GetFieldIndex();
1658 if (properties->get(index)->IsTheHole()) {
1659 properties->set(index, *value);
1660 }
1661 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001662 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1663 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001664 }
1665 } else {
1666 // We should not reach here. Any real, named property should be
1667 // either a field or a dictionary slot.
1668 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001669 }
1670 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001671 // The property was found on some other object. Set it if it is not a
1672 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001673 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001674 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001675 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001676 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001677 JSReceiver::SetProperty(object, name, value, attributes,
1678 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001679 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001680 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001681
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001682 return *value;
1683}
1684
1685
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001686RUNTIME_FUNCTION(MaybeObject*,
1687 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001688 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001689 ASSERT(args.length() == 2);
1690 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001691 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001692 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001693 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001694 }
1695 return *object;
1696}
1697
1698
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001699RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001700 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001701 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001702 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1703 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001704 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001705 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001706 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001707 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001708 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001709 RUNTIME_ASSERT(index >= 0);
1710 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001711 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001712 Handle<Object> result = RegExpImpl::Exec(regexp,
1713 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001714 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001715 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001716 if (result.is_null()) return Failure::Exception();
1717 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001718}
1719
1720
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001721RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001722 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001723 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001724 if (elements_count < 0 ||
1725 elements_count > FixedArray::kMaxLength ||
1726 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001727 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001728 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001729 Object* new_object;
1730 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001732 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1733 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001734 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001735 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1736 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001737 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1738 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001739 {
1740 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001742 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001743 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001744 }
1745 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001747 array->set_elements(elements);
1748 array->set_length(Smi::FromInt(elements_count));
1749 // Write in-object properties after the length of the array.
1750 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1751 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1752 return array;
1753}
1754
1755
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001756RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001757 AssertNoAllocation no_alloc;
1758 ASSERT(args.length() == 5);
1759 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1760 CONVERT_CHECKED(String, source, args[1]);
1761
1762 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001764
1765 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001766 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001767
1768 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001769 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001770
1771 Map* map = regexp->map();
1772 Object* constructor = map->constructor();
1773 if (constructor->IsJSFunction() &&
1774 JSFunction::cast(constructor)->initial_map() == map) {
1775 // If we still have the original map, set in-object properties directly.
1776 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001777 // Both true and false are immovable immortal objects so no need for write
1778 // barrier.
1779 regexp->InObjectPropertyAtPut(
1780 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1781 regexp->InObjectPropertyAtPut(
1782 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1783 regexp->InObjectPropertyAtPut(
1784 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001785 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1786 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001787 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001788 return regexp;
1789 }
1790
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001791 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001792 PropertyAttributes final =
1793 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1794 PropertyAttributes writable =
1795 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001796 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001797 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001799 source,
1800 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001801 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001802 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001803 global,
1804 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001805 ASSERT(!result->IsFailure());
1806 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001807 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001808 ignoreCase,
1809 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001810 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001811 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001812 multiline,
1813 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001814 ASSERT(!result->IsFailure());
1815 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001817 Smi::FromInt(0),
1818 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001819 ASSERT(!result->IsFailure());
1820 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001821 return regexp;
1822}
1823
1824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001825RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001827 ASSERT(args.length() == 1);
1828 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1829 // This is necessary to enable fast checks for absence of elements
1830 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001831 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001832 return Smi::FromInt(0);
1833}
1834
1835
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1837 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001838 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001839 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1841 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1842 Handle<JSFunction> optimized =
1843 isolate->factory()->NewFunction(key,
1844 JS_OBJECT_TYPE,
1845 JSObject::kHeaderSize,
1846 code,
1847 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001848 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001849 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001850 return optimized;
1851}
1852
1853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001854RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001855 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001856 ASSERT(args.length() == 1);
1857 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1858
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001859 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1860 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1861 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1862 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1863 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1864 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1865 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001866
1867 return *holder;
1868}
1869
1870
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001871RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001872 ASSERT(args.length() == 1);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001873 CONVERT_CHECKED(JSReceiver, callable, args[0]);
1874
1875 if (!callable->IsJSFunction()) {
1876 HandleScope scope(isolate);
1877 bool threw = false;
1878 Handle<Object> delegate =
1879 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1880 if (threw) return Failure::Exception();
1881 callable = JSFunction::cast(*delegate);
1882 }
1883 JSFunction* function = JSFunction::cast(callable);
1884
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001885 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001886 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001887 return isolate->heap()->undefined_value();
1888 }
1889 // Returns undefined for strict or native functions, or
1890 // the associated global receiver for "normal" functions.
1891
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001892 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001893 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001894 return global_context->global()->global_receiver();
1895}
1896
1897
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001898RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001899 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001900 ASSERT(args.length() == 4);
1901 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001902 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001903 Handle<String> pattern = args.at<String>(2);
1904 Handle<String> flags = args.at<String>(3);
1905
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001906 // Get the RegExp function from the context in the literals array.
1907 // This is the RegExp function from the context in which the
1908 // function was created. We do not use the RegExp function from the
1909 // current global context because this might be the RegExp function
1910 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001911 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001912 Handle<JSFunction>(
1913 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001914 // Compute the regular expression literal.
1915 bool has_pending_exception;
1916 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001917 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1918 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001919 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001920 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001921 return Failure::Exception();
1922 }
1923 literals->set(index, *regexp);
1924 return *regexp;
1925}
1926
1927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001928RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929 NoHandleAllocation ha;
1930 ASSERT(args.length() == 1);
1931
1932 CONVERT_CHECKED(JSFunction, f, args[0]);
1933 return f->shared()->name();
1934}
1935
1936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001937RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001938 NoHandleAllocation ha;
1939 ASSERT(args.length() == 2);
1940
1941 CONVERT_CHECKED(JSFunction, f, args[0]);
1942 CONVERT_CHECKED(String, name, args[1]);
1943 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001944 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001945}
1946
1947
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001948RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1949 NoHandleAllocation ha;
1950 ASSERT(args.length() == 1);
1951 CONVERT_CHECKED(JSFunction, f, args[0]);
1952 return isolate->heap()->ToBoolean(
1953 f->shared()->name_should_print_as_anonymous());
1954}
1955
1956
1957RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1958 NoHandleAllocation ha;
1959 ASSERT(args.length() == 1);
1960 CONVERT_CHECKED(JSFunction, f, args[0]);
1961 f->shared()->set_name_should_print_as_anonymous(true);
1962 return isolate->heap()->undefined_value();
1963}
1964
1965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001966RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001967 NoHandleAllocation ha;
1968 ASSERT(args.length() == 1);
1969
1970 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001971 Object* obj = f->RemovePrototype();
1972 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001973
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001974 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001975}
1976
1977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001978RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001979 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001980 ASSERT(args.length() == 1);
1981
1982 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001983 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1984 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001985
1986 return *GetScriptWrapper(Handle<Script>::cast(script));
1987}
1988
1989
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001990RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001991 NoHandleAllocation ha;
1992 ASSERT(args.length() == 1);
1993
1994 CONVERT_CHECKED(JSFunction, f, args[0]);
1995 return f->shared()->GetSourceCode();
1996}
1997
1998
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001999RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002000 NoHandleAllocation ha;
2001 ASSERT(args.length() == 1);
2002
2003 CONVERT_CHECKED(JSFunction, fun, args[0]);
2004 int pos = fun->shared()->start_position();
2005 return Smi::FromInt(pos);
2006}
2007
2008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002009RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002010 ASSERT(args.length() == 2);
2011
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002012 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002013 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2014
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002015 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2016
2017 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002018 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002019}
2020
2021
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002022RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002023 NoHandleAllocation ha;
2024 ASSERT(args.length() == 2);
2025
2026 CONVERT_CHECKED(JSFunction, fun, args[0]);
2027 CONVERT_CHECKED(String, name, args[1]);
2028 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002029 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002030}
2031
2032
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002033RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002034 NoHandleAllocation ha;
2035 ASSERT(args.length() == 2);
2036
2037 CONVERT_CHECKED(JSFunction, fun, args[0]);
2038 CONVERT_CHECKED(Smi, length, args[1]);
2039 fun->shared()->set_length(length->value());
2040 return length;
2041}
2042
2043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002044RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002045 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002046 ASSERT(args.length() == 2);
2047
2048 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002049 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002050 Object* obj;
2051 { MaybeObject* maybe_obj =
2052 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2053 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2054 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002055 return args[0]; // return TOS
2056}
2057
2058
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002059RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2060 NoHandleAllocation ha;
2061 RUNTIME_ASSERT(args.length() == 1);
2062 CONVERT_CHECKED(JSFunction, function, args[0]);
2063
2064 MaybeObject* maybe_name =
2065 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2066 String* name;
2067 if (!maybe_name->To(&name)) return maybe_name;
2068
2069 if (function->HasFastProperties()) {
2070 // Construct a new field descriptor with updated attributes.
2071 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2072 int index = instance_desc->Search(name);
2073 ASSERT(index != DescriptorArray::kNotFound);
2074 PropertyDetails details(instance_desc->GetDetails(index));
2075 CallbacksDescriptor new_desc(name,
2076 instance_desc->GetValue(index),
2077 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2078 details.index());
2079 // Construct a new field descriptors array containing the new descriptor.
2080 Object* descriptors_unchecked;
2081 { MaybeObject* maybe_descriptors_unchecked =
2082 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2083 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2084 return maybe_descriptors_unchecked;
2085 }
2086 }
2087 DescriptorArray* new_descriptors =
2088 DescriptorArray::cast(descriptors_unchecked);
2089 // Create a new map featuring the new field descriptors array.
2090 Object* map_unchecked;
2091 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2092 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2093 return maybe_map_unchecked;
2094 }
2095 }
2096 Map* new_map = Map::cast(map_unchecked);
2097 new_map->set_instance_descriptors(new_descriptors);
2098 function->set_map(new_map);
2099 } else { // Dictionary properties.
2100 // Directly manipulate the property details.
2101 int entry = function->property_dictionary()->FindEntry(name);
2102 ASSERT(entry != StringDictionary::kNotFound);
2103 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2104 PropertyDetails new_details(
2105 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2106 details.type(),
2107 details.index());
2108 function->property_dictionary()->DetailsAtPut(entry, new_details);
2109 }
2110 return function;
2111}
2112
2113
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002114RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002115 NoHandleAllocation ha;
2116 ASSERT(args.length() == 1);
2117
2118 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002119 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002120}
2121
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002122
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002123RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002124 NoHandleAllocation ha;
2125 ASSERT(args.length() == 1);
2126
2127 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002128 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002129}
2130
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002132RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002133 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002134 ASSERT(args.length() == 2);
2135
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002136 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002137 Handle<Object> code = args.at<Object>(1);
2138
2139 Handle<Context> context(target->context());
2140
2141 if (!code->IsNull()) {
2142 RUNTIME_ASSERT(code->IsJSFunction());
2143 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002144 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002145
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002146 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002147 return Failure::Exception();
2148 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002149 // Since we don't store the source for this we should never
2150 // optimize this.
2151 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002152 // Set the code, scope info, formal parameter count,
2153 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002154 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002155 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002156 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002157 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002158 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002159 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002160 // Set the source code of the target function to undefined.
2161 // SetCode is only used for built-in constructors like String,
2162 // Array, and Object, and some web code
2163 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002164 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002165 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002166 // Clear the optimization hints related to the compiled code as these are no
2167 // longer valid when the code is overwritten.
2168 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002169 context = Handle<Context>(fun->context());
2170
2171 // Make sure we get a fresh copy of the literal vector to avoid
2172 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002173 int number_of_literals = fun->NumberOfLiterals();
2174 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002175 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002176 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002177 // Insert the object, regexp and array functions in the literals
2178 // array prefix. These are the functions that will be used when
2179 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002180 literals->set(JSFunction::kLiteralGlobalContextIndex,
2181 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002182 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002183 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002184 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002185
2186 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2187 isolate->logger()->LogExistingFunction(
2188 shared, Handle<Code>(shared->code()));
2189 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002190 }
2191
2192 target->set_context(*context);
2193 return *target;
2194}
2195
2196
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002197RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002198 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002199 ASSERT(args.length() == 2);
2200 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002201 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002202 RUNTIME_ASSERT(num >= 0);
2203 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002204 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002205}
2206
2207
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002208MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2209 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002210 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002211 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002212 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002213 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002214 }
2215 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002216 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002217}
2218
2219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002220RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002221 NoHandleAllocation ha;
2222 ASSERT(args.length() == 2);
2223
2224 CONVERT_CHECKED(String, subject, args[0]);
2225 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002226 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002227
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002228 uint32_t i = 0;
2229 if (index->IsSmi()) {
2230 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002231 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002232 i = value;
2233 } else {
2234 ASSERT(index->IsHeapNumber());
2235 double value = HeapNumber::cast(index)->value();
2236 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002237 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002238
2239 // Flatten the string. If someone wants to get a char at an index
2240 // in a cons string, it is likely that more indices will be
2241 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002242 Object* flat;
2243 { MaybeObject* maybe_flat = subject->TryFlatten();
2244 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2245 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002246 subject = String::cast(flat);
2247
2248 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002249 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002250 }
2251
2252 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002253}
2254
2255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002256RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002257 NoHandleAllocation ha;
2258 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002259 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002260}
2261
lrn@chromium.org25156de2010-04-06 13:10:27 +00002262
2263class FixedArrayBuilder {
2264 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002265 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2266 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002267 length_(0),
2268 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002269 // Require a non-zero initial size. Ensures that doubling the size to
2270 // extend the array will work.
2271 ASSERT(initial_capacity > 0);
2272 }
2273
2274 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2275 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002276 length_(0),
2277 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002278 // Require a non-zero initial size. Ensures that doubling the size to
2279 // extend the array will work.
2280 ASSERT(backing_store->length() > 0);
2281 }
2282
2283 bool HasCapacity(int elements) {
2284 int length = array_->length();
2285 int required_length = length_ + elements;
2286 return (length >= required_length);
2287 }
2288
2289 void EnsureCapacity(int elements) {
2290 int length = array_->length();
2291 int required_length = length_ + elements;
2292 if (length < required_length) {
2293 int new_length = length;
2294 do {
2295 new_length *= 2;
2296 } while (new_length < required_length);
2297 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002298 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002299 array_->CopyTo(0, *extended_array, 0, length_);
2300 array_ = extended_array;
2301 }
2302 }
2303
2304 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002305 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002306 ASSERT(length_ < capacity());
2307 array_->set(length_, value);
2308 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002309 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002310 }
2311
2312 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002313 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002314 ASSERT(length_ < capacity());
2315 array_->set(length_, value);
2316 length_++;
2317 }
2318
2319 Handle<FixedArray> array() {
2320 return array_;
2321 }
2322
2323 int length() {
2324 return length_;
2325 }
2326
2327 int capacity() {
2328 return array_->length();
2329 }
2330
2331 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002332 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002333 result_array->set_length(Smi::FromInt(length_));
2334 return result_array;
2335 }
2336
2337 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002338 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002339 target_array->set_length(Smi::FromInt(length_));
2340 return target_array;
2341 }
2342
2343 private:
2344 Handle<FixedArray> array_;
2345 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002346 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002347};
2348
2349
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002350// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002351const int kStringBuilderConcatHelperLengthBits = 11;
2352const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002353
2354template <typename schar>
2355static inline void StringBuilderConcatHelper(String*,
2356 schar*,
2357 FixedArray*,
2358 int);
2359
lrn@chromium.org25156de2010-04-06 13:10:27 +00002360typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2361 StringBuilderSubstringLength;
2362typedef BitField<int,
2363 kStringBuilderConcatHelperLengthBits,
2364 kStringBuilderConcatHelperPositionBits>
2365 StringBuilderSubstringPosition;
2366
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002367
2368class ReplacementStringBuilder {
2369 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002370 ReplacementStringBuilder(Heap* heap,
2371 Handle<String> subject,
2372 int estimated_part_count)
2373 : heap_(heap),
2374 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002375 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002376 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002377 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002378 // Require a non-zero initial size. Ensures that doubling the size to
2379 // extend the array will work.
2380 ASSERT(estimated_part_count > 0);
2381 }
2382
lrn@chromium.org25156de2010-04-06 13:10:27 +00002383 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2384 int from,
2385 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002386 ASSERT(from >= 0);
2387 int length = to - from;
2388 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002389 if (StringBuilderSubstringLength::is_valid(length) &&
2390 StringBuilderSubstringPosition::is_valid(from)) {
2391 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2392 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002393 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002394 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002395 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002396 builder->Add(Smi::FromInt(-length));
2397 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002398 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002399 }
2400
2401
2402 void EnsureCapacity(int elements) {
2403 array_builder_.EnsureCapacity(elements);
2404 }
2405
2406
2407 void AddSubjectSlice(int from, int to) {
2408 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002409 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002410 }
2411
2412
2413 void AddString(Handle<String> string) {
2414 int length = string->length();
2415 ASSERT(length > 0);
2416 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002417 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002418 is_ascii_ = false;
2419 }
2420 IncrementCharacterCount(length);
2421 }
2422
2423
2424 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002425 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002426 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002427 }
2428
2429 Handle<String> joined_string;
2430 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002431 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002432 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002433 char* char_buffer = seq->GetChars();
2434 StringBuilderConcatHelper(*subject_,
2435 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002436 *array_builder_.array(),
2437 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002438 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 } else {
2440 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002441 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002442 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002443 uc16* char_buffer = seq->GetChars();
2444 StringBuilderConcatHelper(*subject_,
2445 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002446 *array_builder_.array(),
2447 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002448 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002449 }
2450 return joined_string;
2451 }
2452
2453
2454 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002455 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002456 V8::FatalProcessOutOfMemory("String.replace result too large.");
2457 }
2458 character_count_ += by;
2459 }
2460
lrn@chromium.org25156de2010-04-06 13:10:27 +00002461 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002462 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002463 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002464
lrn@chromium.org25156de2010-04-06 13:10:27 +00002465 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002466 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2467 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002468 }
2469
2470
ager@chromium.org04921a82011-06-27 13:21:41 +00002471 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2472 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002473 }
2474
2475
2476 void AddElement(Object* element) {
2477 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002478 ASSERT(array_builder_.capacity() > array_builder_.length());
2479 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002480 }
2481
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002482 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002483 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002484 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002485 int character_count_;
2486 bool is_ascii_;
2487};
2488
2489
2490class CompiledReplacement {
2491 public:
2492 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002493 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002494
2495 void Compile(Handle<String> replacement,
2496 int capture_count,
2497 int subject_length);
2498
2499 void Apply(ReplacementStringBuilder* builder,
2500 int match_from,
2501 int match_to,
2502 Handle<JSArray> last_match_info);
2503
2504 // Number of distinct parts of the replacement pattern.
2505 int parts() {
2506 return parts_.length();
2507 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002508
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002509 bool simple_hint() {
2510 return simple_hint_;
2511 }
2512
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002513 private:
2514 enum PartType {
2515 SUBJECT_PREFIX = 1,
2516 SUBJECT_SUFFIX,
2517 SUBJECT_CAPTURE,
2518 REPLACEMENT_SUBSTRING,
2519 REPLACEMENT_STRING,
2520
2521 NUMBER_OF_PART_TYPES
2522 };
2523
2524 struct ReplacementPart {
2525 static inline ReplacementPart SubjectMatch() {
2526 return ReplacementPart(SUBJECT_CAPTURE, 0);
2527 }
2528 static inline ReplacementPart SubjectCapture(int capture_index) {
2529 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2530 }
2531 static inline ReplacementPart SubjectPrefix() {
2532 return ReplacementPart(SUBJECT_PREFIX, 0);
2533 }
2534 static inline ReplacementPart SubjectSuffix(int subject_length) {
2535 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2536 }
2537 static inline ReplacementPart ReplacementString() {
2538 return ReplacementPart(REPLACEMENT_STRING, 0);
2539 }
2540 static inline ReplacementPart ReplacementSubString(int from, int to) {
2541 ASSERT(from >= 0);
2542 ASSERT(to > from);
2543 return ReplacementPart(-from, to);
2544 }
2545
2546 // If tag <= 0 then it is the negation of a start index of a substring of
2547 // the replacement pattern, otherwise it's a value from PartType.
2548 ReplacementPart(int tag, int data)
2549 : tag(tag), data(data) {
2550 // Must be non-positive or a PartType value.
2551 ASSERT(tag < NUMBER_OF_PART_TYPES);
2552 }
2553 // Either a value of PartType or a non-positive number that is
2554 // the negation of an index into the replacement string.
2555 int tag;
2556 // The data value's interpretation depends on the value of tag:
2557 // tag == SUBJECT_PREFIX ||
2558 // tag == SUBJECT_SUFFIX: data is unused.
2559 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2560 // tag == REPLACEMENT_SUBSTRING ||
2561 // tag == REPLACEMENT_STRING: data is index into array of substrings
2562 // of the replacement string.
2563 // tag <= 0: Temporary representation of the substring of the replacement
2564 // string ranging over -tag .. data.
2565 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2566 // substring objects.
2567 int data;
2568 };
2569
2570 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002571 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002572 Vector<Char> characters,
2573 int capture_count,
2574 int subject_length) {
2575 int length = characters.length();
2576 int last = 0;
2577 for (int i = 0; i < length; i++) {
2578 Char c = characters[i];
2579 if (c == '$') {
2580 int next_index = i + 1;
2581 if (next_index == length) { // No next character!
2582 break;
2583 }
2584 Char c2 = characters[next_index];
2585 switch (c2) {
2586 case '$':
2587 if (i > last) {
2588 // There is a substring before. Include the first "$".
2589 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2590 last = next_index + 1; // Continue after the second "$".
2591 } else {
2592 // Let the next substring start with the second "$".
2593 last = next_index;
2594 }
2595 i = next_index;
2596 break;
2597 case '`':
2598 if (i > last) {
2599 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2600 }
2601 parts->Add(ReplacementPart::SubjectPrefix());
2602 i = next_index;
2603 last = i + 1;
2604 break;
2605 case '\'':
2606 if (i > last) {
2607 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2608 }
2609 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2610 i = next_index;
2611 last = i + 1;
2612 break;
2613 case '&':
2614 if (i > last) {
2615 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2616 }
2617 parts->Add(ReplacementPart::SubjectMatch());
2618 i = next_index;
2619 last = i + 1;
2620 break;
2621 case '0':
2622 case '1':
2623 case '2':
2624 case '3':
2625 case '4':
2626 case '5':
2627 case '6':
2628 case '7':
2629 case '8':
2630 case '9': {
2631 int capture_ref = c2 - '0';
2632 if (capture_ref > capture_count) {
2633 i = next_index;
2634 continue;
2635 }
2636 int second_digit_index = next_index + 1;
2637 if (second_digit_index < length) {
2638 // Peek ahead to see if we have two digits.
2639 Char c3 = characters[second_digit_index];
2640 if ('0' <= c3 && c3 <= '9') { // Double digits.
2641 int double_digit_ref = capture_ref * 10 + c3 - '0';
2642 if (double_digit_ref <= capture_count) {
2643 next_index = second_digit_index;
2644 capture_ref = double_digit_ref;
2645 }
2646 }
2647 }
2648 if (capture_ref > 0) {
2649 if (i > last) {
2650 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2651 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002652 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002653 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2654 last = next_index + 1;
2655 }
2656 i = next_index;
2657 break;
2658 }
2659 default:
2660 i = next_index;
2661 break;
2662 }
2663 }
2664 }
2665 if (length > last) {
2666 if (last == 0) {
2667 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002668 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002669 } else {
2670 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2671 }
2672 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002673 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002674 }
2675
2676 ZoneList<ReplacementPart> parts_;
2677 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002678 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002679};
2680
2681
2682void CompiledReplacement::Compile(Handle<String> replacement,
2683 int capture_count,
2684 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002685 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002686 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002687 String::FlatContent content = replacement->GetFlatContent();
2688 ASSERT(content.IsFlat());
2689 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002690 simple_hint_ = ParseReplacementPattern(&parts_,
2691 content.ToAsciiVector(),
2692 capture_count,
2693 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002694 } else {
2695 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002696 simple_hint_ = ParseReplacementPattern(&parts_,
2697 content.ToUC16Vector(),
2698 capture_count,
2699 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002700 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002701 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002702 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002703 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002704 int substring_index = 0;
2705 for (int i = 0, n = parts_.length(); i < n; i++) {
2706 int tag = parts_[i].tag;
2707 if (tag <= 0) { // A replacement string slice.
2708 int from = -tag;
2709 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002710 replacement_substrings_.Add(
2711 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002712 parts_[i].tag = REPLACEMENT_SUBSTRING;
2713 parts_[i].data = substring_index;
2714 substring_index++;
2715 } else if (tag == REPLACEMENT_STRING) {
2716 replacement_substrings_.Add(replacement);
2717 parts_[i].data = substring_index;
2718 substring_index++;
2719 }
2720 }
2721}
2722
2723
2724void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2725 int match_from,
2726 int match_to,
2727 Handle<JSArray> last_match_info) {
2728 for (int i = 0, n = parts_.length(); i < n; i++) {
2729 ReplacementPart part = parts_[i];
2730 switch (part.tag) {
2731 case SUBJECT_PREFIX:
2732 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2733 break;
2734 case SUBJECT_SUFFIX: {
2735 int subject_length = part.data;
2736 if (match_to < subject_length) {
2737 builder->AddSubjectSlice(match_to, subject_length);
2738 }
2739 break;
2740 }
2741 case SUBJECT_CAPTURE: {
2742 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002743 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002744 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2745 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2746 if (from >= 0 && to > from) {
2747 builder->AddSubjectSlice(from, to);
2748 }
2749 break;
2750 }
2751 case REPLACEMENT_SUBSTRING:
2752 case REPLACEMENT_STRING:
2753 builder->AddString(replacement_substrings_[part.data]);
2754 break;
2755 default:
2756 UNREACHABLE();
2757 }
2758 }
2759}
2760
2761
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002762void FindAsciiStringIndices(Vector<const char> subject,
2763 char pattern,
2764 ZoneList<int>* indices,
2765 unsigned int limit) {
2766 ASSERT(limit > 0);
2767 // Collect indices of pattern in subject using memchr.
2768 // Stop after finding at most limit values.
2769 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2770 const char* subject_end = subject_start + subject.length();
2771 const char* pos = subject_start;
2772 while (limit > 0) {
2773 pos = reinterpret_cast<const char*>(
2774 memchr(pos, pattern, subject_end - pos));
2775 if (pos == NULL) return;
2776 indices->Add(static_cast<int>(pos - subject_start));
2777 pos++;
2778 limit--;
2779 }
2780}
2781
2782
2783template <typename SubjectChar, typename PatternChar>
2784void FindStringIndices(Isolate* isolate,
2785 Vector<const SubjectChar> subject,
2786 Vector<const PatternChar> pattern,
2787 ZoneList<int>* indices,
2788 unsigned int limit) {
2789 ASSERT(limit > 0);
2790 // Collect indices of pattern in subject.
2791 // Stop after finding at most limit values.
2792 int pattern_length = pattern.length();
2793 int index = 0;
2794 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2795 while (limit > 0) {
2796 index = search.Search(subject, index);
2797 if (index < 0) return;
2798 indices->Add(index);
2799 index += pattern_length;
2800 limit--;
2801 }
2802}
2803
2804
2805void FindStringIndicesDispatch(Isolate* isolate,
2806 String* subject,
2807 String* pattern,
2808 ZoneList<int>* indices,
2809 unsigned int limit) {
2810 {
2811 AssertNoAllocation no_gc;
2812 String::FlatContent subject_content = subject->GetFlatContent();
2813 String::FlatContent pattern_content = pattern->GetFlatContent();
2814 ASSERT(subject_content.IsFlat());
2815 ASSERT(pattern_content.IsFlat());
2816 if (subject_content.IsAscii()) {
2817 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2818 if (pattern_content.IsAscii()) {
2819 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2820 if (pattern_vector.length() == 1) {
2821 FindAsciiStringIndices(subject_vector,
2822 pattern_vector[0],
2823 indices,
2824 limit);
2825 } else {
2826 FindStringIndices(isolate,
2827 subject_vector,
2828 pattern_vector,
2829 indices,
2830 limit);
2831 }
2832 } else {
2833 FindStringIndices(isolate,
2834 subject_vector,
2835 pattern_content.ToUC16Vector(),
2836 indices,
2837 limit);
2838 }
2839 } else {
2840 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002841 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002842 FindStringIndices(isolate,
2843 subject_vector,
2844 pattern_content.ToAsciiVector(),
2845 indices,
2846 limit);
2847 } else {
2848 FindStringIndices(isolate,
2849 subject_vector,
2850 pattern_content.ToUC16Vector(),
2851 indices,
2852 limit);
2853 }
2854 }
2855 }
2856}
2857
2858
2859template<typename ResultSeqString>
2860MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2861 Isolate* isolate,
2862 Handle<String> subject,
2863 Handle<JSRegExp> pattern_regexp,
2864 Handle<String> replacement) {
2865 ASSERT(subject->IsFlat());
2866 ASSERT(replacement->IsFlat());
2867
2868 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2869 ZoneList<int> indices(8);
2870 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2871 String* pattern =
2872 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2873 int subject_len = subject->length();
2874 int pattern_len = pattern->length();
2875 int replacement_len = replacement->length();
2876
2877 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2878
2879 int matches = indices.length();
2880 if (matches == 0) return *subject;
2881
2882 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2883 int subject_pos = 0;
2884 int result_pos = 0;
2885
2886 Handle<ResultSeqString> result;
2887 if (ResultSeqString::kHasAsciiEncoding) {
2888 result = Handle<ResultSeqString>::cast(
2889 isolate->factory()->NewRawAsciiString(result_len));
2890 } else {
2891 result = Handle<ResultSeqString>::cast(
2892 isolate->factory()->NewRawTwoByteString(result_len));
2893 }
2894
2895 for (int i = 0; i < matches; i++) {
2896 // Copy non-matched subject content.
2897 if (subject_pos < indices.at(i)) {
2898 String::WriteToFlat(*subject,
2899 result->GetChars() + result_pos,
2900 subject_pos,
2901 indices.at(i));
2902 result_pos += indices.at(i) - subject_pos;
2903 }
2904
2905 // Replace match.
2906 if (replacement_len > 0) {
2907 String::WriteToFlat(*replacement,
2908 result->GetChars() + result_pos,
2909 0,
2910 replacement_len);
2911 result_pos += replacement_len;
2912 }
2913
2914 subject_pos = indices.at(i) + pattern_len;
2915 }
2916 // Add remaining subject content at the end.
2917 if (subject_pos < subject_len) {
2918 String::WriteToFlat(*subject,
2919 result->GetChars() + result_pos,
2920 subject_pos,
2921 subject_len);
2922 }
2923 return *result;
2924}
2925
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002926
lrn@chromium.org303ada72010-10-27 09:33:13 +00002927MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002928 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002929 String* subject,
2930 JSRegExp* regexp,
2931 String* replacement,
2932 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002933 ASSERT(subject->IsFlat());
2934 ASSERT(replacement->IsFlat());
2935
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002936 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002937
2938 int length = subject->length();
2939 Handle<String> subject_handle(subject);
2940 Handle<JSRegExp> regexp_handle(regexp);
2941 Handle<String> replacement_handle(replacement);
2942 Handle<JSArray> last_match_info_handle(last_match_info);
2943 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2944 subject_handle,
2945 0,
2946 last_match_info_handle);
2947 if (match.is_null()) {
2948 return Failure::Exception();
2949 }
2950 if (match->IsNull()) {
2951 return *subject_handle;
2952 }
2953
2954 int capture_count = regexp_handle->CaptureCount();
2955
2956 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002957 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002958 CompiledReplacement compiled_replacement;
2959 compiled_replacement.Compile(replacement_handle,
2960 capture_count,
2961 length);
2962
2963 bool is_global = regexp_handle->GetFlags().is_global();
2964
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002965 // Shortcut for simple non-regexp global replacements
2966 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002967 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002968 compiled_replacement.simple_hint()) {
2969 if (subject_handle->HasOnlyAsciiChars() &&
2970 replacement_handle->HasOnlyAsciiChars()) {
2971 return StringReplaceStringWithString<SeqAsciiString>(
2972 isolate, subject_handle, regexp_handle, replacement_handle);
2973 } else {
2974 return StringReplaceStringWithString<SeqTwoByteString>(
2975 isolate, subject_handle, regexp_handle, replacement_handle);
2976 }
2977 }
2978
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002979 // Guessing the number of parts that the final result string is built
2980 // from. Global regexps can match any number of times, so we guess
2981 // conservatively.
2982 int expected_parts =
2983 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002984 ReplacementStringBuilder builder(isolate->heap(),
2985 subject_handle,
2986 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002987
2988 // Index of end of last match.
2989 int prev = 0;
2990
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002991 // Number of parts added by compiled replacement plus preceeding
2992 // string and possibly suffix after last match. It is possible for
2993 // all components to use two elements when encoded as two smis.
2994 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002995 bool matched = true;
2996 do {
2997 ASSERT(last_match_info_handle->HasFastElements());
2998 // Increase the capacity of the builder before entering local handle-scope,
2999 // so its internal buffer can safely allocate a new handle if it grows.
3000 builder.EnsureCapacity(parts_added_per_loop);
3001
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003002 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003003 int start, end;
3004 {
3005 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003006 FixedArray* match_info_array =
3007 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003008
3009 ASSERT_EQ(capture_count * 2 + 2,
3010 RegExpImpl::GetLastCaptureCount(match_info_array));
3011 start = RegExpImpl::GetCapture(match_info_array, 0);
3012 end = RegExpImpl::GetCapture(match_info_array, 1);
3013 }
3014
3015 if (prev < start) {
3016 builder.AddSubjectSlice(prev, start);
3017 }
3018 compiled_replacement.Apply(&builder,
3019 start,
3020 end,
3021 last_match_info_handle);
3022 prev = end;
3023
3024 // Only continue checking for global regexps.
3025 if (!is_global) break;
3026
3027 // Continue from where the match ended, unless it was an empty match.
3028 int next = end;
3029 if (start == end) {
3030 next = end + 1;
3031 if (next > length) break;
3032 }
3033
3034 match = RegExpImpl::Exec(regexp_handle,
3035 subject_handle,
3036 next,
3037 last_match_info_handle);
3038 if (match.is_null()) {
3039 return Failure::Exception();
3040 }
3041 matched = !match->IsNull();
3042 } while (matched);
3043
3044 if (prev < length) {
3045 builder.AddSubjectSlice(prev, length);
3046 }
3047
3048 return *(builder.ToString());
3049}
3050
3051
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003052template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003053MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003054 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003055 String* subject,
3056 JSRegExp* regexp,
3057 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003058 ASSERT(subject->IsFlat());
3059
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003060 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003061
3062 Handle<String> subject_handle(subject);
3063 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003064
3065 // Shortcut for simple non-regexp global replacements
3066 if (regexp_handle->GetFlags().is_global() &&
3067 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3068 Handle<String> empty_string_handle(HEAP->empty_string());
3069 if (subject_handle->HasOnlyAsciiChars()) {
3070 return StringReplaceStringWithString<SeqAsciiString>(
3071 isolate, subject_handle, regexp_handle, empty_string_handle);
3072 } else {
3073 return StringReplaceStringWithString<SeqTwoByteString>(
3074 isolate, subject_handle, regexp_handle, empty_string_handle);
3075 }
3076 }
3077
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003078 Handle<JSArray> last_match_info_handle(last_match_info);
3079 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3080 subject_handle,
3081 0,
3082 last_match_info_handle);
3083 if (match.is_null()) return Failure::Exception();
3084 if (match->IsNull()) return *subject_handle;
3085
3086 ASSERT(last_match_info_handle->HasFastElements());
3087
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003088 int start, end;
3089 {
3090 AssertNoAllocation match_info_array_is_not_in_a_handle;
3091 FixedArray* match_info_array =
3092 FixedArray::cast(last_match_info_handle->elements());
3093
3094 start = RegExpImpl::GetCapture(match_info_array, 0);
3095 end = RegExpImpl::GetCapture(match_info_array, 1);
3096 }
3097
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003098 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003099 int new_length = length - (end - start);
3100 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003101 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003102 }
3103 Handle<ResultSeqString> answer;
3104 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003105 answer = Handle<ResultSeqString>::cast(
3106 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003107 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003108 answer = Handle<ResultSeqString>::cast(
3109 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003110 }
3111
3112 // If the regexp isn't global, only match once.
3113 if (!regexp_handle->GetFlags().is_global()) {
3114 if (start > 0) {
3115 String::WriteToFlat(*subject_handle,
3116 answer->GetChars(),
3117 0,
3118 start);
3119 }
3120 if (end < length) {
3121 String::WriteToFlat(*subject_handle,
3122 answer->GetChars() + start,
3123 end,
3124 length);
3125 }
3126 return *answer;
3127 }
3128
3129 int prev = 0; // Index of end of last match.
3130 int next = 0; // Start of next search (prev unless last match was empty).
3131 int position = 0;
3132
3133 do {
3134 if (prev < start) {
3135 // Add substring subject[prev;start] to answer string.
3136 String::WriteToFlat(*subject_handle,
3137 answer->GetChars() + position,
3138 prev,
3139 start);
3140 position += start - prev;
3141 }
3142 prev = end;
3143 next = end;
3144 // Continue from where the match ended, unless it was an empty match.
3145 if (start == end) {
3146 next++;
3147 if (next > length) break;
3148 }
3149 match = RegExpImpl::Exec(regexp_handle,
3150 subject_handle,
3151 next,
3152 last_match_info_handle);
3153 if (match.is_null()) return Failure::Exception();
3154 if (match->IsNull()) break;
3155
3156 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003157 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003158 {
3159 AssertNoAllocation match_info_array_is_not_in_a_handle;
3160 FixedArray* match_info_array =
3161 FixedArray::cast(last_match_info_handle->elements());
3162 start = RegExpImpl::GetCapture(match_info_array, 0);
3163 end = RegExpImpl::GetCapture(match_info_array, 1);
3164 }
3165 } while (true);
3166
3167 if (prev < length) {
3168 // Add substring subject[prev;length] to answer string.
3169 String::WriteToFlat(*subject_handle,
3170 answer->GetChars() + position,
3171 prev,
3172 length);
3173 position += length - prev;
3174 }
3175
3176 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003177 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003178 }
3179
3180 // Shorten string and fill
3181 int string_size = ResultSeqString::SizeFor(position);
3182 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3183 int delta = allocated_string_size - string_size;
3184
3185 answer->set_length(position);
3186 if (delta == 0) return *answer;
3187
3188 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003189 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003190 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003191 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003192 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003193
3194 return *answer;
3195}
3196
3197
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003198RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003199 ASSERT(args.length() == 4);
3200
3201 CONVERT_CHECKED(String, subject, args[0]);
3202 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003203 Object* flat_subject;
3204 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3205 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3206 return maybe_flat_subject;
3207 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003208 }
3209 subject = String::cast(flat_subject);
3210 }
3211
3212 CONVERT_CHECKED(String, replacement, args[2]);
3213 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003214 Object* flat_replacement;
3215 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3216 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3217 return maybe_flat_replacement;
3218 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003219 }
3220 replacement = String::cast(flat_replacement);
3221 }
3222
3223 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3224 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3225
3226 ASSERT(last_match_info->HasFastElements());
3227
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003228 if (replacement->length() == 0) {
3229 if (subject->HasOnlyAsciiChars()) {
3230 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003231 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003232 } else {
3233 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003234 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003235 }
3236 }
3237
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003238 return StringReplaceRegExpWithString(isolate,
3239 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003240 regexp,
3241 replacement,
3242 last_match_info);
3243}
3244
3245
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003246Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3247 Handle<String> subject,
3248 Handle<String> search,
3249 Handle<String> replace,
3250 bool* found,
3251 int recursion_limit) {
3252 if (recursion_limit == 0) return Handle<String>::null();
3253 if (subject->IsConsString()) {
3254 ConsString* cons = ConsString::cast(*subject);
3255 Handle<String> first = Handle<String>(cons->first());
3256 Handle<String> second = Handle<String>(cons->second());
3257 Handle<String> new_first =
3258 StringReplaceOneCharWithString(isolate,
3259 first,
3260 search,
3261 replace,
3262 found,
3263 recursion_limit - 1);
3264 if (*found) return isolate->factory()->NewConsString(new_first, second);
3265 if (new_first.is_null()) return new_first;
3266
3267 Handle<String> new_second =
3268 StringReplaceOneCharWithString(isolate,
3269 second,
3270 search,
3271 replace,
3272 found,
3273 recursion_limit - 1);
3274 if (*found) return isolate->factory()->NewConsString(first, new_second);
3275 if (new_second.is_null()) return new_second;
3276
3277 return subject;
3278 } else {
3279 int index = StringMatch(isolate, subject, search, 0);
3280 if (index == -1) return subject;
3281 *found = true;
3282 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3283 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3284 Handle<String> second =
3285 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3286 return isolate->factory()->NewConsString(cons1, second);
3287 }
3288}
3289
3290
3291RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3292 ASSERT(args.length() == 3);
3293 HandleScope scope(isolate);
3294 CONVERT_ARG_CHECKED(String, subject, 0);
3295 CONVERT_ARG_CHECKED(String, search, 1);
3296 CONVERT_ARG_CHECKED(String, replace, 2);
3297
3298 // If the cons string tree is too deep, we simply abort the recursion and
3299 // retry with a flattened subject string.
3300 const int kRecursionLimit = 0x1000;
3301 bool found = false;
3302 Handle<String> result =
3303 Runtime::StringReplaceOneCharWithString(isolate,
3304 subject,
3305 search,
3306 replace,
3307 &found,
3308 kRecursionLimit);
3309 if (!result.is_null()) return *result;
3310 return *Runtime::StringReplaceOneCharWithString(isolate,
3311 FlattenGetString(subject),
3312 search,
3313 replace,
3314 &found,
3315 kRecursionLimit);
3316}
3317
3318
ager@chromium.org7c537e22008-10-16 08:43:32 +00003319// Perform string match of pattern on subject, starting at start index.
3320// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003321// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003322int Runtime::StringMatch(Isolate* isolate,
3323 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003324 Handle<String> pat,
3325 int start_index) {
3326 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003327 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003328
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003329 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003330 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003331
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003332 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003333 if (start_index + pattern_length > subject_length) return -1;
3334
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003335 if (!sub->IsFlat()) FlattenString(sub);
3336 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003337
ager@chromium.org7c537e22008-10-16 08:43:32 +00003338 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003339 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003340 String::FlatContent seq_sub = sub->GetFlatContent();
3341 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003342
ager@chromium.org7c537e22008-10-16 08:43:32 +00003343 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003344 if (seq_pat.IsAscii()) {
3345 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3346 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003347 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003348 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003349 pat_vector,
3350 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003351 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003352 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003353 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003354 pat_vector,
3355 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003356 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003357 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3358 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003359 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003360 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003361 pat_vector,
3362 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003363 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003364 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003365 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003366 pat_vector,
3367 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003368}
3369
3370
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003371RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003372 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003373 ASSERT(args.length() == 3);
3374
ager@chromium.org7c537e22008-10-16 08:43:32 +00003375 CONVERT_ARG_CHECKED(String, sub, 0);
3376 CONVERT_ARG_CHECKED(String, pat, 1);
3377
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003378 Object* index = args[2];
3379 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003380 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003381
ager@chromium.org870a0b62008-11-04 11:43:05 +00003382 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003383 int position =
3384 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003385 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003386}
3387
3388
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003389template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003390static int StringMatchBackwards(Vector<const schar> subject,
3391 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003392 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003393 int pattern_length = pattern.length();
3394 ASSERT(pattern_length >= 1);
3395 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003396
3397 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003398 for (int i = 0; i < pattern_length; i++) {
3399 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003400 if (c > String::kMaxAsciiCharCode) {
3401 return -1;
3402 }
3403 }
3404 }
3405
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003406 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003407 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003408 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003409 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003410 while (j < pattern_length) {
3411 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003412 break;
3413 }
3414 j++;
3415 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003416 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003417 return i;
3418 }
3419 }
3420 return -1;
3421}
3422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003423RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003424 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003425 ASSERT(args.length() == 3);
3426
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003427 CONVERT_ARG_CHECKED(String, sub, 0);
3428 CONVERT_ARG_CHECKED(String, pat, 1);
3429
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003430 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003431 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003432 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003433
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003434 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003435 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003436
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003437 if (start_index + pat_length > sub_length) {
3438 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003439 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003440
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003441 if (pat_length == 0) {
3442 return Smi::FromInt(start_index);
3443 }
3444
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003445 if (!sub->IsFlat()) FlattenString(sub);
3446 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003447
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003448 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003449 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3450
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003451 String::FlatContent sub_content = sub->GetFlatContent();
3452 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003453
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003454 if (pat_content.IsAscii()) {
3455 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3456 if (sub_content.IsAscii()) {
3457 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003458 pat_vector,
3459 start_index);
3460 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003461 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003462 pat_vector,
3463 start_index);
3464 }
3465 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003466 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3467 if (sub_content.IsAscii()) {
3468 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003469 pat_vector,
3470 start_index);
3471 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003472 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003473 pat_vector,
3474 start_index);
3475 }
3476 }
3477
3478 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003479}
3480
3481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003482RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003483 NoHandleAllocation ha;
3484 ASSERT(args.length() == 2);
3485
3486 CONVERT_CHECKED(String, str1, args[0]);
3487 CONVERT_CHECKED(String, str2, args[1]);
3488
3489 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003490 int str1_length = str1->length();
3491 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003492
3493 // Decide trivial cases without flattening.
3494 if (str1_length == 0) {
3495 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3496 return Smi::FromInt(-str2_length);
3497 } else {
3498 if (str2_length == 0) return Smi::FromInt(str1_length);
3499 }
3500
3501 int end = str1_length < str2_length ? str1_length : str2_length;
3502
3503 // No need to flatten if we are going to find the answer on the first
3504 // character. At this point we know there is at least one character
3505 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003506 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003507 if (d != 0) return Smi::FromInt(d);
3508
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003509 str1->TryFlatten();
3510 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003511
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003512 StringInputBuffer& buf1 =
3513 *isolate->runtime_state()->string_locale_compare_buf1();
3514 StringInputBuffer& buf2 =
3515 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003516
3517 buf1.Reset(str1);
3518 buf2.Reset(str2);
3519
3520 for (int i = 0; i < end; i++) {
3521 uint16_t char1 = buf1.GetNext();
3522 uint16_t char2 = buf2.GetNext();
3523 if (char1 != char2) return Smi::FromInt(char1 - char2);
3524 }
3525
3526 return Smi::FromInt(str1_length - str2_length);
3527}
3528
3529
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003530RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003531 NoHandleAllocation ha;
3532 ASSERT(args.length() == 3);
3533
3534 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003535 int start, end;
3536 // We have a fast integer-only case here to avoid a conversion to double in
3537 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003538 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3539 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3540 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3541 start = from_number;
3542 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003543 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003544 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3545 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003546 start = FastD2I(from_number);
3547 end = FastD2I(to_number);
3548 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003549 RUNTIME_ASSERT(end >= start);
3550 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003551 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003552 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003553 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003554}
3555
3556
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003557RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003558 ASSERT_EQ(3, args.length());
3559
3560 CONVERT_ARG_CHECKED(String, subject, 0);
3561 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3562 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3563 HandleScope handles;
3564
3565 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3566
3567 if (match.is_null()) {
3568 return Failure::Exception();
3569 }
3570 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003571 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003572 }
3573 int length = subject->length();
3574
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003575 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003576 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003577 int start;
3578 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003579 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003580 {
3581 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003582 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003583 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3584 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3585 }
3586 offsets.Add(start);
3587 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003588 if (start == end) if (++end > length) break;
3589 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003590 if (match.is_null()) {
3591 return Failure::Exception();
3592 }
3593 } while (!match->IsNull());
3594 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003595 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003596 Handle<String> substring = isolate->factory()->
3597 NewSubString(subject, offsets.at(0), offsets.at(1));
3598 elements->set(0, *substring);
3599 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003600 int from = offsets.at(i * 2);
3601 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003602 Handle<String> substring = isolate->factory()->
3603 NewProperSubString(subject, from, to);
3604 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003605 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003606 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003607 result->set_length(Smi::FromInt(matches));
3608 return *result;
3609}
3610
3611
lrn@chromium.org25156de2010-04-06 13:10:27 +00003612// Two smis before and after the match, for very long strings.
3613const int kMaxBuilderEntriesPerRegExpMatch = 5;
3614
3615
3616static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3617 Handle<JSArray> last_match_info,
3618 int match_start,
3619 int match_end) {
3620 // Fill last_match_info with a single capture.
3621 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3622 AssertNoAllocation no_gc;
3623 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3624 RegExpImpl::SetLastCaptureCount(elements, 2);
3625 RegExpImpl::SetLastInput(elements, *subject);
3626 RegExpImpl::SetLastSubject(elements, *subject);
3627 RegExpImpl::SetCapture(elements, 0, match_start);
3628 RegExpImpl::SetCapture(elements, 1, match_end);
3629}
3630
3631
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003632template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003633static bool SearchStringMultiple(Isolate* isolate,
3634 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003635 Vector<const PatternChar> pattern,
3636 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003637 FixedArrayBuilder* builder,
3638 int* match_pos) {
3639 int pos = *match_pos;
3640 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003641 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003642 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003643 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003644 while (pos <= max_search_start) {
3645 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3646 *match_pos = pos;
3647 return false;
3648 }
3649 // Position of end of previous match.
3650 int match_end = pos + pattern_length;
3651 int new_pos = search.Search(subject, match_end);
3652 if (new_pos >= 0) {
3653 // A match.
3654 if (new_pos > match_end) {
3655 ReplacementStringBuilder::AddSubjectSlice(builder,
3656 match_end,
3657 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003658 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003659 pos = new_pos;
3660 builder->Add(pattern_string);
3661 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003662 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003663 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003664 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003665
lrn@chromium.org25156de2010-04-06 13:10:27 +00003666 if (pos < max_search_start) {
3667 ReplacementStringBuilder::AddSubjectSlice(builder,
3668 pos + pattern_length,
3669 subject_length);
3670 }
3671 *match_pos = pos;
3672 return true;
3673}
3674
3675
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003676static bool SearchStringMultiple(Isolate* isolate,
3677 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003678 Handle<String> pattern,
3679 Handle<JSArray> last_match_info,
3680 FixedArrayBuilder* builder) {
3681 ASSERT(subject->IsFlat());
3682 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003683
3684 // Treating as if a previous match was before first character.
3685 int match_pos = -pattern->length();
3686
3687 for (;;) { // Break when search complete.
3688 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3689 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003690 String::FlatContent subject_content = subject->GetFlatContent();
3691 String::FlatContent pattern_content = pattern->GetFlatContent();
3692 if (subject_content.IsAscii()) {
3693 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3694 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003695 if (SearchStringMultiple(isolate,
3696 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003697 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003698 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003699 builder,
3700 &match_pos)) break;
3701 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003702 if (SearchStringMultiple(isolate,
3703 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003704 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003705 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003706 builder,
3707 &match_pos)) break;
3708 }
3709 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003710 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3711 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003712 if (SearchStringMultiple(isolate,
3713 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003714 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003715 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003716 builder,
3717 &match_pos)) break;
3718 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003719 if (SearchStringMultiple(isolate,
3720 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003721 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003722 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003723 builder,
3724 &match_pos)) break;
3725 }
3726 }
3727 }
3728
3729 if (match_pos >= 0) {
3730 SetLastMatchInfoNoCaptures(subject,
3731 last_match_info,
3732 match_pos,
3733 match_pos + pattern->length());
3734 return true;
3735 }
3736 return false; // No matches at all.
3737}
3738
3739
3740static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003741 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003742 Handle<String> subject,
3743 Handle<JSRegExp> regexp,
3744 Handle<JSArray> last_match_array,
3745 FixedArrayBuilder* builder) {
3746 ASSERT(subject->IsFlat());
3747 int match_start = -1;
3748 int match_end = 0;
3749 int pos = 0;
3750 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3751 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3752
3753 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003754 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003755 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003756 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003757
3758 for (;;) { // Break on failure, return on exception.
3759 RegExpImpl::IrregexpResult result =
3760 RegExpImpl::IrregexpExecOnce(regexp,
3761 subject,
3762 pos,
3763 register_vector);
3764 if (result == RegExpImpl::RE_SUCCESS) {
3765 match_start = register_vector[0];
3766 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3767 if (match_end < match_start) {
3768 ReplacementStringBuilder::AddSubjectSlice(builder,
3769 match_end,
3770 match_start);
3771 }
3772 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003773 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003774 if (!first) {
3775 builder->Add(*isolate->factory()->NewProperSubString(subject,
3776 match_start,
3777 match_end));
3778 } else {
3779 builder->Add(*isolate->factory()->NewSubString(subject,
3780 match_start,
3781 match_end));
3782 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003783 if (match_start != match_end) {
3784 pos = match_end;
3785 } else {
3786 pos = match_end + 1;
3787 if (pos > subject_length) break;
3788 }
3789 } else if (result == RegExpImpl::RE_FAILURE) {
3790 break;
3791 } else {
3792 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3793 return result;
3794 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003795 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003796 }
3797
3798 if (match_start >= 0) {
3799 if (match_end < subject_length) {
3800 ReplacementStringBuilder::AddSubjectSlice(builder,
3801 match_end,
3802 subject_length);
3803 }
3804 SetLastMatchInfoNoCaptures(subject,
3805 last_match_array,
3806 match_start,
3807 match_end);
3808 return RegExpImpl::RE_SUCCESS;
3809 } else {
3810 return RegExpImpl::RE_FAILURE; // No matches at all.
3811 }
3812}
3813
3814
3815static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003816 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003817 Handle<String> subject,
3818 Handle<JSRegExp> regexp,
3819 Handle<JSArray> last_match_array,
3820 FixedArrayBuilder* builder) {
3821
3822 ASSERT(subject->IsFlat());
3823 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3824 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3825
3826 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003827 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003828
3829 RegExpImpl::IrregexpResult result =
3830 RegExpImpl::IrregexpExecOnce(regexp,
3831 subject,
3832 0,
3833 register_vector);
3834
3835 int capture_count = regexp->CaptureCount();
3836 int subject_length = subject->length();
3837
3838 // Position to search from.
3839 int pos = 0;
3840 // End of previous match. Differs from pos if match was empty.
3841 int match_end = 0;
3842 if (result == RegExpImpl::RE_SUCCESS) {
3843 // Need to keep a copy of the previous match for creating last_match_info
3844 // at the end, so we have two vectors that we swap between.
3845 OffsetsVector registers2(required_registers);
3846 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003847 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003848 do {
3849 int match_start = register_vector[0];
3850 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3851 if (match_end < match_start) {
3852 ReplacementStringBuilder::AddSubjectSlice(builder,
3853 match_end,
3854 match_start);
3855 }
3856 match_end = register_vector[1];
3857
3858 {
3859 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003860 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003861 // Arguments array to replace function is match, captures, index and
3862 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003863 Handle<FixedArray> elements =
3864 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003865 Handle<String> match;
3866 if (!first) {
3867 match = isolate->factory()->NewProperSubString(subject,
3868 match_start,
3869 match_end);
3870 } else {
3871 match = isolate->factory()->NewSubString(subject,
3872 match_start,
3873 match_end);
3874 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003875 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003876 for (int i = 1; i <= capture_count; i++) {
3877 int start = register_vector[i * 2];
3878 if (start >= 0) {
3879 int end = register_vector[i * 2 + 1];
3880 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003881 Handle<String> substring;
3882 if (!first) {
3883 substring = isolate->factory()->NewProperSubString(subject,
3884 start,
3885 end);
3886 } else {
3887 substring = isolate->factory()->NewSubString(subject, start, end);
3888 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003889 elements->set(i, *substring);
3890 } else {
3891 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003892 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003893 }
3894 }
3895 elements->set(capture_count + 1, Smi::FromInt(match_start));
3896 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003897 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003898 }
3899 // Swap register vectors, so the last successful match is in
3900 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003901 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003902 prev_register_vector = register_vector;
3903 register_vector = tmp;
3904
3905 if (match_end > match_start) {
3906 pos = match_end;
3907 } else {
3908 pos = match_end + 1;
3909 if (pos > subject_length) {
3910 break;
3911 }
3912 }
3913
3914 result = RegExpImpl::IrregexpExecOnce(regexp,
3915 subject,
3916 pos,
3917 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003918 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003919 } while (result == RegExpImpl::RE_SUCCESS);
3920
3921 if (result != RegExpImpl::RE_EXCEPTION) {
3922 // Finished matching, with at least one match.
3923 if (match_end < subject_length) {
3924 ReplacementStringBuilder::AddSubjectSlice(builder,
3925 match_end,
3926 subject_length);
3927 }
3928
3929 int last_match_capture_count = (capture_count + 1) * 2;
3930 int last_match_array_size =
3931 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3932 last_match_array->EnsureSize(last_match_array_size);
3933 AssertNoAllocation no_gc;
3934 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3935 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3936 RegExpImpl::SetLastSubject(elements, *subject);
3937 RegExpImpl::SetLastInput(elements, *subject);
3938 for (int i = 0; i < last_match_capture_count; i++) {
3939 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3940 }
3941 return RegExpImpl::RE_SUCCESS;
3942 }
3943 }
3944 // No matches at all, return failure or exception result directly.
3945 return result;
3946}
3947
3948
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003949RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003950 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003951 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003952
3953 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003954 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003955 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3956 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3957 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3958
3959 ASSERT(last_match_info->HasFastElements());
3960 ASSERT(regexp->GetFlags().is_global());
3961 Handle<FixedArray> result_elements;
3962 if (result_array->HasFastElements()) {
3963 result_elements =
3964 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003965 }
3966 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003967 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003968 }
3969 FixedArrayBuilder builder(result_elements);
3970
3971 if (regexp->TypeTag() == JSRegExp::ATOM) {
3972 Handle<String> pattern(
3973 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003974 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003975 if (SearchStringMultiple(isolate, subject, pattern,
3976 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003977 return *builder.ToJSArray(result_array);
3978 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003979 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003980 }
3981
3982 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3983
3984 RegExpImpl::IrregexpResult result;
3985 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003986 result = SearchRegExpNoCaptureMultiple(isolate,
3987 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003988 regexp,
3989 last_match_info,
3990 &builder);
3991 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003992 result = SearchRegExpMultiple(isolate,
3993 subject,
3994 regexp,
3995 last_match_info,
3996 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003997 }
3998 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003999 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004000 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4001 return Failure::Exception();
4002}
4003
4004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004005RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004006 NoHandleAllocation ha;
4007 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004008 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004009 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004010
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004011 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004012 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004013 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004014 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004015 // Character array used for conversion.
4016 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004017 return isolate->heap()->
4018 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004019 }
4020 }
4021
4022 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004023 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004024 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004025 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004026 }
4027 if (isinf(value)) {
4028 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004029 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004030 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004031 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004033 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004034 MaybeObject* result =
4035 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004036 DeleteArray(str);
4037 return result;
4038}
4039
4040
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004041RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004042 NoHandleAllocation ha;
4043 ASSERT(args.length() == 2);
4044
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004045 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004046 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004047 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004048 }
4049 if (isinf(value)) {
4050 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004051 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004052 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004053 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004055 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 int f = FastD2I(f_number);
4057 RUNTIME_ASSERT(f >= 0);
4058 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004059 MaybeObject* res =
4060 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004061 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004062 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063}
4064
4065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004066RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004067 NoHandleAllocation ha;
4068 ASSERT(args.length() == 2);
4069
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004070 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004071 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004072 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004073 }
4074 if (isinf(value)) {
4075 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004076 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004078 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004079 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004080 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081 int f = FastD2I(f_number);
4082 RUNTIME_ASSERT(f >= -1 && f <= 20);
4083 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004084 MaybeObject* res =
4085 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004086 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004087 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088}
4089
4090
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004091RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004092 NoHandleAllocation ha;
4093 ASSERT(args.length() == 2);
4094
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004095 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004096 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004097 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 }
4099 if (isinf(value)) {
4100 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004101 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004103 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004104 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004105 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004106 int f = FastD2I(f_number);
4107 RUNTIME_ASSERT(f >= 1 && f <= 21);
4108 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004109 MaybeObject* res =
4110 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004112 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004113}
4114
4115
4116// Returns a single character string where first character equals
4117// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004118static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004119 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004120 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004121 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004122 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004123 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004124 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004125}
4126
4127
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004128MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4129 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004130 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004131 // Handle [] indexing on Strings
4132 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004133 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4134 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004135 }
4136
4137 // Handle [] indexing on String objects
4138 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004139 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4140 Handle<Object> result =
4141 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4142 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143 }
4144
4145 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004146 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004147 }
4148
4149 return object->GetElement(index);
4150}
4151
4152
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004153MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4154 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004155 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004156 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004157
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004158 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004159 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004160 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004161 isolate->factory()->NewTypeError("non_object_property_load",
4162 HandleVector(args, 2));
4163 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 }
4165
4166 // Check if the given key is an array index.
4167 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004168 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004169 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004170 }
4171
4172 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004173 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004174 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004175 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004176 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004177 bool has_pending_exception = false;
4178 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004179 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004180 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004181 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004182 }
4183
ager@chromium.org32912102009-01-16 10:38:43 +00004184 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004185 // the element if so.
4186 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004187 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004188 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004189 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190 }
4191}
4192
4193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004194RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004195 NoHandleAllocation ha;
4196 ASSERT(args.length() == 2);
4197
4198 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004199 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004200
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004201 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004202}
4203
4204
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004205MaybeObject* TransitionElements(Handle<Object> object,
4206 ElementsKind to_kind,
4207 Isolate* isolate) {
4208 HandleScope scope(isolate);
4209 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
4210 ElementsKind from_kind =
4211 Handle<JSObject>::cast(object)->map()->elements_kind();
4212 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004213 Handle<Object> result = JSObject::TransitionElementsKind(
4214 Handle<JSObject>::cast(object), to_kind);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004215 if (result.is_null()) return isolate->ThrowIllegalOperation();
4216 return *result;
4217 }
4218 return isolate->ThrowIllegalOperation();
4219}
4220
4221
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004222// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004223RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004224 NoHandleAllocation ha;
4225 ASSERT(args.length() == 2);
4226
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004227 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004228 // itself.
4229 //
4230 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004231 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004232 // global proxy object never has properties. This is the case
4233 // because the global proxy object forwards everything to its hidden
4234 // prototype including local lookups.
4235 //
4236 // Additionally, we need to make sure that we do not cache results
4237 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004238 if (args[0]->IsJSObject()) {
4239 if (!args[0]->IsJSGlobalProxy() &&
4240 !args[0]->IsAccessCheckNeeded() &&
4241 args[1]->IsString()) {
4242 JSObject* receiver = JSObject::cast(args[0]);
4243 String* key = String::cast(args[1]);
4244 if (receiver->HasFastProperties()) {
4245 // Attempt to use lookup cache.
4246 Map* receiver_map = receiver->map();
4247 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4248 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4249 if (offset != -1) {
4250 Object* value = receiver->FastPropertyAt(offset);
4251 return value->IsTheHole()
4252 ? isolate->heap()->undefined_value()
4253 : value;
4254 }
4255 // Lookup cache miss. Perform lookup and update the cache if
4256 // appropriate.
4257 LookupResult result(isolate);
4258 receiver->LocalLookup(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004259 if (result.IsFound() && result.type() == FIELD) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004260 int offset = result.GetFieldIndex();
4261 keyed_lookup_cache->Update(receiver_map, key, offset);
4262 return receiver->FastPropertyAt(offset);
4263 }
4264 } else {
4265 // Attempt dictionary lookup.
4266 StringDictionary* dictionary = receiver->property_dictionary();
4267 int entry = dictionary->FindEntry(key);
4268 if ((entry != StringDictionary::kNotFound) &&
4269 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4270 Object* value = dictionary->ValueAt(entry);
4271 if (!receiver->IsGlobalObject()) return value;
4272 value = JSGlobalPropertyCell::cast(value)->value();
4273 if (!value->IsTheHole()) return value;
4274 // If value is the hole do the general lookup.
4275 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004276 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004277 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4278 // JSObject without a string key. If the key is a Smi, check for a
4279 // definite out-of-bounds access to elements, which is a strong indicator
4280 // that subsequent accesses will also call the runtime. Proactively
4281 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4282 // doubles for those future calls in the case that the elements would
4283 // become FAST_DOUBLE_ELEMENTS.
4284 Handle<JSObject> js_object(args.at<JSObject>(0));
4285 ElementsKind elements_kind = js_object->GetElementsKind();
4286 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4287 elements_kind == FAST_DOUBLE_ELEMENTS) {
4288 FixedArrayBase* elements = js_object->elements();
4289 if (args.at<Smi>(1)->value() >= elements->length()) {
4290 MaybeObject* maybe_object = TransitionElements(js_object,
4291 FAST_ELEMENTS,
4292 isolate);
4293 if (maybe_object->IsFailure()) return maybe_object;
4294 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004295 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004296 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004297 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4298 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004299 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004300 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004301 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004302 if (index >= 0 && index < str->length()) {
4303 Handle<Object> result = GetCharAt(str, index);
4304 return *result;
4305 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004306 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004307
4308 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004309 return Runtime::GetObjectProperty(isolate,
4310 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004311 args.at<Object>(1));
4312}
4313
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004314// Implements part of 8.12.9 DefineOwnProperty.
4315// There are 3 cases that lead here:
4316// Step 4b - define a new accessor property.
4317// Steps 9c & 12 - replace an existing data property with an accessor property.
4318// Step 12 - update an existing accessor property with an accessor or generic
4319// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004320RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004321 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004322 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004323 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4324 CONVERT_CHECKED(String, name, args[1]);
4325 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004326 Object* fun = args[3];
ager@chromium.org5c838252010-02-19 08:53:10 +00004327 CONVERT_CHECKED(Smi, flag_attr, args[4]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004328
ager@chromium.org5c838252010-02-19 08:53:10 +00004329 int unchecked = flag_attr->value();
4330 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004331 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004332
4333 RUNTIME_ASSERT(!obj->IsNull());
4334 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004335 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4336}
4337
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004338// Implements part of 8.12.9 DefineOwnProperty.
4339// There are 3 cases that lead here:
4340// Step 4a - define a new data property.
4341// Steps 9b & 12 - replace an existing accessor property with a data property.
4342// Step 12 - update an existing data property with a data or generic
4343// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004344RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004345 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004346 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004347 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4348 CONVERT_ARG_CHECKED(String, name, 1);
4349 Handle<Object> obj_value = args.at<Object>(2);
ager@chromium.org5c838252010-02-19 08:53:10 +00004350 CONVERT_CHECKED(Smi, flag, args[3]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004351
ager@chromium.org5c838252010-02-19 08:53:10 +00004352 int unchecked = flag->value();
4353 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004354 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4355
4356 // Check if this is an element.
4357 uint32_t index;
4358 bool is_element = name->AsArrayIndex(&index);
4359
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004360 // Special case for elements if any of the flags might be involved.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004361 // If elements are in fast case we always implicitly assume that:
4362 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004363 if (is_element && (attr != NONE ||
4364 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004365 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004366 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004367 // We do not need to do access checks here since these has already
4368 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004369 Handle<Object> proto(js_object->GetPrototype());
4370 // If proxy is detached, ignore the assignment. Alternatively,
4371 // we could throw an exception.
4372 if (proto->IsNull()) return *obj_value;
4373 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004374 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004375
4376 // Don't allow element properties to be redefined on objects with external
4377 // array elements.
4378 if (js_object->HasExternalArrayElements()) {
4379 Handle<Object> args[2] = { js_object, name };
4380 Handle<Object> error =
4381 isolate->factory()->NewTypeError("redef_external_array_element",
4382 HandleVector(args, 2));
4383 return isolate->Throw(*error);
4384 }
4385
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004386 Handle<SeededNumberDictionary> dictionary =
4387 JSObject::NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004388 // Make sure that we never go back to fast case.
4389 dictionary->set_requires_slow_elements();
4390 PropertyDetails details = PropertyDetails(attr, NORMAL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004391 Handle<SeededNumberDictionary> extended_dictionary =
4392 SeededNumberDictionary::Set(dictionary, index, obj_value, details);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004393 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004394 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004395 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4396 } else {
4397 js_object->set_elements(*extended_dictionary);
4398 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004399 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004400 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004401 }
4402
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004403 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004404 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004405
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004406 // Special case for callback properties.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004407 if (result.IsFound() && result.type() == CALLBACKS) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004408 Object* callback = result.GetCallbackObject();
4409 // To be compatible with Safari we do not change the value on API objects
4410 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4411 // the value.
4412 if (callback->IsAccessorInfo()) {
4413 return isolate->heap()->undefined_value();
4414 }
4415 // Avoid redefining foreign callback as data property, just use the stored
4416 // setter to update the value instead.
4417 // TODO(mstarzinger): So far this only works if property attributes don't
4418 // change, this should be fixed once we cleanup the underlying code.
4419 if (callback->IsForeign() && result.GetAttributes() == attr) {
4420 return js_object->SetPropertyWithCallback(callback,
4421 *name,
4422 *obj_value,
4423 result.holder(),
4424 kStrictMode);
4425 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004426 }
4427
ager@chromium.org5c838252010-02-19 08:53:10 +00004428 // Take special care when attributes are different and there is already
4429 // a property. For simplicity we normalize the property which enables us
4430 // to not worry about changing the instance_descriptor and creating a new
4431 // map. The current version of SetObjectProperty does not handle attributes
4432 // correctly in the case where a property is a field and is reset with
4433 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004434 if (result.IsProperty() &&
4435 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004436 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004437 if (js_object->IsJSGlobalProxy()) {
4438 // Since the result is a property, the prototype will exist so
4439 // we don't have to check for null.
4440 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004441 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004442 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004443 // Use IgnoreAttributes version since a readonly property may be
4444 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004445 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4446 *obj_value,
4447 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004448 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004449
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004450 return Runtime::ForceSetObjectProperty(isolate,
4451 js_object,
4452 name,
4453 obj_value,
4454 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004455}
4456
4457
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004458// Special case for elements if any of the flags are true.
4459// If elements are in fast case we always implicitly assume that:
4460// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4461static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4462 Handle<JSObject> js_object,
4463 uint32_t index,
4464 Handle<Object> value,
4465 PropertyAttributes attr) {
4466 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004467 Handle<SeededNumberDictionary> dictionary =
4468 JSObject::NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004469 // Make sure that we never go back to fast case.
4470 dictionary->set_requires_slow_elements();
4471 PropertyDetails details = PropertyDetails(attr, NORMAL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004472 Handle<SeededNumberDictionary> extended_dictionary =
4473 SeededNumberDictionary::Set(dictionary, index, value, details);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004474 if (*extended_dictionary != *dictionary) {
4475 js_object->set_elements(*extended_dictionary);
4476 }
4477 return *value;
4478}
4479
4480
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004481MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4482 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004483 Handle<Object> key,
4484 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004485 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004486 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004487 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004488
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004489 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004490 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004491 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004492 isolate->factory()->NewTypeError("non_object_property_store",
4493 HandleVector(args, 2));
4494 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004495 }
4496
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004497 if (object->IsJSProxy()) {
4498 bool has_pending_exception = false;
4499 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4500 if (has_pending_exception) return Failure::Exception();
4501 return JSProxy::cast(*object)->SetProperty(
4502 String::cast(*name), *value, attr, strict_mode);
4503 }
4504
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004505 // If the object isn't a JavaScript object, we ignore the store.
4506 if (!object->IsJSObject()) return *value;
4507
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004508 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4509
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004510 // Check if the given key is an array index.
4511 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004512 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004513 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4514 // of a string using [] notation. We need to support this too in
4515 // JavaScript.
4516 // In the case of a String object we just need to redirect the assignment to
4517 // the underlying string if the index is in range. Since the underlying
4518 // string does nothing with the assignment then we can ignore such
4519 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004520 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004521 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004522 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004523
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004524 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4525 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4526 }
4527
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004528 Handle<Object> result =
4529 JSObject::SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004530 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004531 return *value;
4532 }
4533
4534 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004535 Handle<Object> result;
4536 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004537 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4538 return NormalizeObjectSetElement(isolate,
4539 js_object,
4540 index,
4541 value,
4542 attr);
4543 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004544 result =
4545 JSObject::SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004546 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004547 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004548 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004549 result = JSReceiver::SetProperty(
4550 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004551 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004552 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004553 return *value;
4554 }
4555
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004556 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004557 bool has_pending_exception = false;
4558 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4559 if (has_pending_exception) return Failure::Exception();
4560 Handle<String> name = Handle<String>::cast(converted);
4561
4562 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004563 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004564 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004565 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004566 }
4567}
4568
4569
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004570MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4571 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004572 Handle<Object> key,
4573 Handle<Object> value,
4574 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004575 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004576
4577 // Check if the given key is an array index.
4578 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004579 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004580 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4581 // of a string using [] notation. We need to support this too in
4582 // JavaScript.
4583 // In the case of a String object we just need to redirect the assignment to
4584 // the underlying string if the index is in range. Since the underlying
4585 // string does nothing with the assignment then we can ignore such
4586 // assignments.
4587 if (js_object->IsStringObjectWithCharacterAt(index)) {
4588 return *value;
4589 }
4590
whesse@chromium.org7b260152011-06-20 15:33:18 +00004591 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004592 }
4593
4594 if (key->IsString()) {
4595 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004596 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004597 } else {
4598 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004599 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004600 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4601 *value,
4602 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004603 }
4604 }
4605
4606 // Call-back into JavaScript to convert the key to a string.
4607 bool has_pending_exception = false;
4608 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4609 if (has_pending_exception) return Failure::Exception();
4610 Handle<String> name = Handle<String>::cast(converted);
4611
4612 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004613 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004614 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004615 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004616 }
4617}
4618
4619
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004620MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004621 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004622 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004623 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004624
4625 // Check if the given key is an array index.
4626 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004627 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004628 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4629 // characters of a string using [] notation. In the case of a
4630 // String object we just need to redirect the deletion to the
4631 // underlying string if the index is in range. Since the
4632 // underlying string does nothing with the deletion, we can ignore
4633 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004634 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004635 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004636 }
4637
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004638 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004639 }
4640
4641 Handle<String> key_string;
4642 if (key->IsString()) {
4643 key_string = Handle<String>::cast(key);
4644 } else {
4645 // Call-back into JavaScript to convert the key to a string.
4646 bool has_pending_exception = false;
4647 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4648 if (has_pending_exception) return Failure::Exception();
4649 key_string = Handle<String>::cast(converted);
4650 }
4651
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004652 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004653 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004654}
4655
4656
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004657RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004658 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004659 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004660
4661 Handle<Object> object = args.at<Object>(0);
4662 Handle<Object> key = args.at<Object>(1);
4663 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004664 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004665 RUNTIME_ASSERT(
4666 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004667 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004668 PropertyAttributes attributes =
4669 static_cast<PropertyAttributes>(unchecked_attributes);
4670
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004671 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004672 if (args.length() == 5) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004673 CONVERT_STRICT_MODE_ARG(strict_mode_flag, 4);
4674 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004675 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004677 return Runtime::SetObjectProperty(isolate,
4678 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004679 key,
4680 value,
4681 attributes,
4682 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004683}
4684
4685
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004686RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4687 NoHandleAllocation ha;
4688 RUNTIME_ASSERT(args.length() == 1);
4689 Handle<Object> object = args.at<Object>(0);
4690 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4691}
4692
4693
4694RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4695 NoHandleAllocation ha;
4696 RUNTIME_ASSERT(args.length() == 1);
4697 Handle<Object> object = args.at<Object>(0);
4698 return TransitionElements(object, FAST_ELEMENTS, isolate);
4699}
4700
4701
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004702// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004703// This is used to decide if we should transform null and undefined
4704// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004705RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004706 NoHandleAllocation ha;
4707 RUNTIME_ASSERT(args.length() == 1);
4708
4709 Handle<Object> object = args.at<Object>(0);
4710
4711 if (object->IsJSFunction()) {
4712 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004713 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004714 }
4715 return isolate->heap()->undefined_value();
4716}
4717
4718
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004719RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4720 RUNTIME_ASSERT(args.length() == 5);
4721 CONVERT_ARG_CHECKED(JSObject, object, 0);
4722 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4723 Handle<Object> value = args.at<Object>(2);
4724 CONVERT_ARG_CHECKED(FixedArray, literals, 3);
4725 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4726 HandleScope scope;
4727
4728 Object* raw_boilerplate_object = literals->get(literal_index);
4729 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4730#if DEBUG
4731 ElementsKind elements_kind = object->GetElementsKind();
4732#endif
4733 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4734 // Smis should never trigger transitions.
4735 ASSERT(!value->IsSmi());
4736
4737 if (value->IsNumber()) {
4738 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004739 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4740 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004741 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4742 FixedDoubleArray* double_array =
4743 FixedDoubleArray::cast(object->elements());
4744 HeapNumber* number = HeapNumber::cast(*value);
4745 double_array->set(store_index, number->Number());
4746 } else {
4747 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4748 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004749 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4750 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004751 FixedArray* object_array =
4752 FixedArray::cast(object->elements());
4753 object_array->set(store_index, *value);
4754 }
4755 return *object;
4756}
4757
4758
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004759// Set a local property, even if it is READ_ONLY. If the property does not
4760// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004761RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004762 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004763 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004764 CONVERT_CHECKED(JSObject, object, args[0]);
4765 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004766 // Compute attributes.
4767 PropertyAttributes attributes = NONE;
4768 if (args.length() == 4) {
4769 CONVERT_CHECKED(Smi, value_obj, args[3]);
4770 int unchecked_value = value_obj->value();
4771 // Only attribute bits should be set.
4772 RUNTIME_ASSERT(
4773 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4774 attributes = static_cast<PropertyAttributes>(unchecked_value);
4775 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004776
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004777 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004778 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004779}
4780
4781
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004782RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004783 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004784 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004785
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004786 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004787 CONVERT_CHECKED(String, key, args[1]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004788 CONVERT_STRICT_MODE_ARG(strict_mode, 2);
4789 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004790 ? JSReceiver::STRICT_DELETION
4791 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004792}
4793
4794
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004795static Object* HasLocalPropertyImplementation(Isolate* isolate,
4796 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004797 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004798 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004799 // Handle hidden prototypes. If there's a hidden prototype above this thing
4800 // then we have to check it for properties, because they are supposed to
4801 // look like they are on this object.
4802 Handle<Object> proto(object->GetPrototype());
4803 if (proto->IsJSObject() &&
4804 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004805 return HasLocalPropertyImplementation(isolate,
4806 Handle<JSObject>::cast(proto),
4807 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004808 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004809 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004810}
4811
4812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004813RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004814 NoHandleAllocation ha;
4815 ASSERT(args.length() == 2);
4816 CONVERT_CHECKED(String, key, args[1]);
4817
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004818 uint32_t index;
4819 const bool key_is_array_index = key->AsArrayIndex(&index);
4820
ager@chromium.org9085a012009-05-11 19:22:57 +00004821 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004822 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004823 if (obj->IsJSObject()) {
4824 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004825 // Fast case: either the key is a real named property or it is not
4826 // an array index and there are no interceptors or hidden
4827 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004828 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004829 Map* map = object->map();
4830 if (!key_is_array_index &&
4831 !map->has_named_interceptor() &&
4832 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4833 return isolate->heap()->false_value();
4834 }
4835 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004836 HandleScope scope(isolate);
4837 return HasLocalPropertyImplementation(isolate,
4838 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004839 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004840 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004841 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004842 String* string = String::cast(obj);
4843 if (index < static_cast<uint32_t>(string->length())) {
4844 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004845 }
4846 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004847 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004848}
4849
4850
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004851RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004852 NoHandleAllocation na;
4853 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004854 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4855 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004856
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004857 bool result = receiver->HasProperty(key);
4858 if (isolate->has_pending_exception()) return Failure::Exception();
4859 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004860}
4861
4862
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004863RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004864 NoHandleAllocation na;
4865 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004866 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4867 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004868
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004869 bool result = receiver->HasElement(index->value());
4870 if (isolate->has_pending_exception()) return Failure::Exception();
4871 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004872}
4873
4874
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004875RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004876 NoHandleAllocation ha;
4877 ASSERT(args.length() == 2);
4878
4879 CONVERT_CHECKED(JSObject, object, args[0]);
4880 CONVERT_CHECKED(String, key, args[1]);
4881
4882 uint32_t index;
4883 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004884 JSObject::LocalElementType type = object->HasLocalElement(index);
4885 switch (type) {
4886 case JSObject::UNDEFINED_ELEMENT:
4887 case JSObject::STRING_CHARACTER_ELEMENT:
4888 return isolate->heap()->false_value();
4889 case JSObject::INTERCEPTED_ELEMENT:
4890 case JSObject::FAST_ELEMENT:
4891 return isolate->heap()->true_value();
4892 case JSObject::DICTIONARY_ELEMENT: {
4893 if (object->IsJSGlobalProxy()) {
4894 Object* proto = object->GetPrototype();
4895 if (proto->IsNull()) {
4896 return isolate->heap()->false_value();
4897 }
4898 ASSERT(proto->IsJSGlobalObject());
4899 object = JSObject::cast(proto);
4900 }
4901 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004902 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004903 if (elements->map() ==
4904 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004905 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004906 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004907 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004908 }
4909 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004910 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004911 PropertyDetails details = dictionary->DetailsAt(entry);
4912 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4913 }
4914 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004915 }
4916
ager@chromium.org870a0b62008-11-04 11:43:05 +00004917 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004918 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004919}
4920
4921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004922RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004923 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004924 ASSERT(args.length() == 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004925 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4926 bool threw = false;
4927 Handle<JSArray> result = GetKeysFor(object, &threw);
4928 if (threw) return Failure::Exception();
4929 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004930}
4931
4932
4933// Returns either a FixedArray as Runtime_GetPropertyNames,
4934// or, if the given object has an enum cache that contains
4935// all enumerable properties of the object and its prototypes
4936// have none, the map of the object. This is used to speed up
4937// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004938RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004939 ASSERT(args.length() == 1);
4940
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004941 CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004942
4943 if (raw_object->IsSimpleEnum()) return raw_object->map();
4944
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004945 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004946 Handle<JSReceiver> object(raw_object);
4947 bool threw = false;
4948 Handle<FixedArray> content =
4949 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4950 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004951
4952 // Test again, since cache may have been built by preceding call.
4953 if (object->IsSimpleEnum()) return object->map();
4954
4955 return *content;
4956}
4957
4958
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004959// Find the length of the prototype chain that is to to handled as one. If a
4960// prototype object is hidden it is to be viewed as part of the the object it
4961// is prototype for.
4962static int LocalPrototypeChainLength(JSObject* obj) {
4963 int count = 1;
4964 Object* proto = obj->GetPrototype();
4965 while (proto->IsJSObject() &&
4966 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4967 count++;
4968 proto = JSObject::cast(proto)->GetPrototype();
4969 }
4970 return count;
4971}
4972
4973
4974// Return the names of the local named properties.
4975// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004976RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004977 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004978 ASSERT(args.length() == 1);
4979 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004980 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004981 }
4982 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4983
4984 // Skip the global proxy as it has no properties and always delegates to the
4985 // real global object.
4986 if (obj->IsJSGlobalProxy()) {
4987 // Only collect names if access is permitted.
4988 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004989 !isolate->MayNamedAccess(*obj,
4990 isolate->heap()->undefined_value(),
4991 v8::ACCESS_KEYS)) {
4992 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4993 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004994 }
4995 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4996 }
4997
4998 // Find the number of objects making up this.
4999 int length = LocalPrototypeChainLength(*obj);
5000
5001 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005002 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005003 int total_property_count = 0;
5004 Handle<JSObject> jsproto = obj;
5005 for (int i = 0; i < length; i++) {
5006 // Only collect names if access is permitted.
5007 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005008 !isolate->MayNamedAccess(*jsproto,
5009 isolate->heap()->undefined_value(),
5010 v8::ACCESS_KEYS)) {
5011 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
5012 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005013 }
5014 int n;
5015 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
5016 local_property_count[i] = n;
5017 total_property_count += n;
5018 if (i < length - 1) {
5019 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5020 }
5021 }
5022
5023 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005024 Handle<FixedArray> names =
5025 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005026
5027 // Get the property names.
5028 jsproto = obj;
5029 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005030 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005031 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005032 jsproto->GetLocalPropertyNames(*names, next_copy_index);
5033 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00005034 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005035 proto_with_hidden_properties++;
5036 }
5037 if (i < length - 1) {
5038 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5039 }
5040 }
5041
5042 // Filter out name of hidden propeties object.
5043 if (proto_with_hidden_properties > 0) {
5044 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005045 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005046 names->length() - proto_with_hidden_properties);
5047 int dest_pos = 0;
5048 for (int i = 0; i < total_property_count; i++) {
5049 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005050 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005051 continue;
5052 }
5053 names->set(dest_pos++, name);
5054 }
5055 }
5056
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005057 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005058}
5059
5060
5061// Return the names of the local indexed properties.
5062// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005063RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005064 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005065 ASSERT(args.length() == 1);
5066 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005067 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005068 }
5069 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5070
5071 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005072 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005073 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005074 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005075}
5076
5077
5078// Return information on whether an object has a named or indexed interceptor.
5079// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005080RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005081 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005082 ASSERT(args.length() == 1);
5083 if (!args[0]->IsJSObject()) {
5084 return Smi::FromInt(0);
5085 }
5086 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5087
5088 int result = 0;
5089 if (obj->HasNamedInterceptor()) result |= 2;
5090 if (obj->HasIndexedInterceptor()) result |= 1;
5091
5092 return Smi::FromInt(result);
5093}
5094
5095
5096// Return property names from named interceptor.
5097// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005098RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005099 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005100 ASSERT(args.length() == 1);
5101 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5102
5103 if (obj->HasNamedInterceptor()) {
5104 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5105 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5106 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005107 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005108}
5109
5110
5111// Return element names from indexed interceptor.
5112// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005113RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005114 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005115 ASSERT(args.length() == 1);
5116 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5117
5118 if (obj->HasIndexedInterceptor()) {
5119 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5120 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5121 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005122 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005123}
5124
5125
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005126RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005127 ASSERT_EQ(args.length(), 1);
5128 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005129 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005130 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005131
5132 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005133 // Do access checks before going to the global object.
5134 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005135 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005136 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005137 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5138 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005139 }
5140
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005141 Handle<Object> proto(object->GetPrototype());
5142 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005143 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005144 object = Handle<JSObject>::cast(proto);
5145 }
5146
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005147 bool threw = false;
5148 Handle<FixedArray> contents =
5149 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5150 if (threw) return Failure::Exception();
5151
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005152 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5153 // property array and since the result is mutable we have to create
5154 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005155 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005156 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005157 for (int i = 0; i < length; i++) {
5158 Object* entry = contents->get(i);
5159 if (entry->IsString()) {
5160 copy->set(i, entry);
5161 } else {
5162 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005163 HandleScope scope(isolate);
5164 Handle<Object> entry_handle(entry, isolate);
5165 Handle<Object> entry_str =
5166 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005167 copy->set(i, *entry_str);
5168 }
5169 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005170 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005171}
5172
5173
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005174RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005175 NoHandleAllocation ha;
5176 ASSERT(args.length() == 1);
5177
5178 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005179 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005180 it.AdvanceToArgumentsFrame();
5181 JavaScriptFrame* frame = it.frame();
5182
5183 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005184 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005185
5186 // Try to convert the key to an index. If successful and within
5187 // index return the the argument from the frame.
5188 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005189 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005190 return frame->GetParameter(index);
5191 }
5192
5193 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005194 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005195 bool exception = false;
5196 Handle<Object> converted =
5197 Execution::ToString(args.at<Object>(0), &exception);
5198 if (exception) return Failure::Exception();
5199 Handle<String> key = Handle<String>::cast(converted);
5200
5201 // Try to convert the string key into an array index.
5202 if (key->AsArrayIndex(&index)) {
5203 if (index < n) {
5204 return frame->GetParameter(index);
5205 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005206 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005207 }
5208 }
5209
5210 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005211 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5212 if (key->Equals(isolate->heap()->callee_symbol())) {
5213 Object* function = frame->function();
5214 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005215 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005216 return isolate->Throw(*isolate->factory()->NewTypeError(
5217 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5218 }
5219 return function;
5220 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005221
5222 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005223 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005224}
5225
5226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005227RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005228 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005229 Object* object = args[0];
5230 return (object->IsJSObject() && !object->IsGlobalObject())
5231 ? JSObject::cast(object)->TransformToFastProperties(0)
5232 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005233}
5234
5235
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005236RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005237 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005238 Object* obj = args[0];
5239 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5240 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5241 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005242}
5243
5244
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005245RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005246 NoHandleAllocation ha;
5247 ASSERT(args.length() == 1);
5248
5249 return args[0]->ToBoolean();
5250}
5251
5252
5253// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5254// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005255RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005256 NoHandleAllocation ha;
5257
5258 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005259 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005260 HeapObject* heap_obj = HeapObject::cast(obj);
5261
5262 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005263 if (heap_obj->map()->is_undetectable()) {
5264 return isolate->heap()->undefined_symbol();
5265 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005266
5267 InstanceType instance_type = heap_obj->map()->instance_type();
5268 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005269 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005270 }
5271
5272 switch (instance_type) {
5273 case ODDBALL_TYPE:
5274 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005275 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005276 }
5277 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005278 return FLAG_harmony_typeof
5279 ? isolate->heap()->null_symbol()
5280 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005281 }
5282 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005283 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005284 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005285 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005286 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005287 default:
5288 // For any kind of object not handled above, the spec rule for
5289 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005290 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005291 }
5292}
5293
5294
lrn@chromium.org25156de2010-04-06 13:10:27 +00005295static bool AreDigits(const char*s, int from, int to) {
5296 for (int i = from; i < to; i++) {
5297 if (s[i] < '0' || s[i] > '9') return false;
5298 }
5299
5300 return true;
5301}
5302
5303
5304static int ParseDecimalInteger(const char*s, int from, int to) {
5305 ASSERT(to - from < 10); // Overflow is not possible.
5306 ASSERT(from < to);
5307 int d = s[from] - '0';
5308
5309 for (int i = from + 1; i < to; i++) {
5310 d = 10 * d + (s[i] - '0');
5311 }
5312
5313 return d;
5314}
5315
5316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005317RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005318 NoHandleAllocation ha;
5319 ASSERT(args.length() == 1);
5320 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005321 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005322
5323 // Fast case: short integer or some sorts of junk values.
5324 int len = subject->length();
5325 if (subject->IsSeqAsciiString()) {
5326 if (len == 0) return Smi::FromInt(0);
5327
5328 char const* data = SeqAsciiString::cast(subject)->GetChars();
5329 bool minus = (data[0] == '-');
5330 int start_pos = (minus ? 1 : 0);
5331
5332 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005333 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005334 } else if (data[start_pos] > '9') {
5335 // Fast check for a junk value. A valid string may start from a
5336 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5337 // the 'I' character ('Infinity'). All of that have codes not greater than
5338 // '9' except 'I'.
5339 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005340 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005341 }
5342 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5343 // The maximal/minimal smi has 10 digits. If the string has less digits we
5344 // know it will fit into the smi-data type.
5345 int d = ParseDecimalInteger(data, start_pos, len);
5346 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005347 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005348 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005349 } else if (!subject->HasHashCode() &&
5350 len <= String::kMaxArrayIndexSize &&
5351 (len == 1 || data[0] != '0')) {
5352 // String hash is not calculated yet but all the data are present.
5353 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005354 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005355#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005356 subject->Hash(); // Force hash calculation.
5357 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5358 static_cast<int>(hash));
5359#endif
5360 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005361 }
5362 return Smi::FromInt(d);
5363 }
5364 }
5365
5366 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005367 return isolate->heap()->NumberFromDouble(
5368 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005369}
5370
5371
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005372RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005373 NoHandleAllocation ha;
5374 ASSERT(args.length() == 1);
5375
5376 CONVERT_CHECKED(JSArray, codes, args[0]);
5377 int length = Smi::cast(codes->length())->value();
5378
5379 // Check if the string can be ASCII.
5380 int i;
5381 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005382 Object* element;
5383 { MaybeObject* maybe_element = codes->GetElement(i);
5384 // We probably can't get an exception here, but just in order to enforce
5385 // the checking of inputs in the runtime calls we check here.
5386 if (!maybe_element->ToObject(&element)) return maybe_element;
5387 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005388 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5389 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5390 break;
5391 }
5392
lrn@chromium.org303ada72010-10-27 09:33:13 +00005393 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005394 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005395 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005396 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005397 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005398 }
5399
lrn@chromium.org303ada72010-10-27 09:33:13 +00005400 Object* object = NULL;
5401 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005402 String* result = String::cast(object);
5403 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005404 Object* element;
5405 { MaybeObject* maybe_element = codes->GetElement(i);
5406 if (!maybe_element->ToObject(&element)) return maybe_element;
5407 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005408 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005409 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005410 }
5411 return result;
5412}
5413
5414
5415// kNotEscaped is generated by the following:
5416//
5417// #!/bin/perl
5418// for (my $i = 0; $i < 256; $i++) {
5419// print "\n" if $i % 16 == 0;
5420// my $c = chr($i);
5421// my $escaped = 1;
5422// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5423// print $escaped ? "0, " : "1, ";
5424// }
5425
5426
5427static bool IsNotEscaped(uint16_t character) {
5428 // Only for 8 bit characters, the rest are always escaped (in a different way)
5429 ASSERT(character < 256);
5430 static const char kNotEscaped[256] = {
5431 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5432 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5433 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5434 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5435 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5436 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5437 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5438 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5439 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5440 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5441 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5442 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5443 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5444 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5445 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5446 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5447 };
5448 return kNotEscaped[character] != 0;
5449}
5450
5451
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005452RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005453 const char hex_chars[] = "0123456789ABCDEF";
5454 NoHandleAllocation ha;
5455 ASSERT(args.length() == 1);
5456 CONVERT_CHECKED(String, source, args[0]);
5457
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005458 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005459
5460 int escaped_length = 0;
5461 int length = source->length();
5462 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005463 Access<StringInputBuffer> buffer(
5464 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005465 buffer->Reset(source);
5466 while (buffer->has_more()) {
5467 uint16_t character = buffer->GetNext();
5468 if (character >= 256) {
5469 escaped_length += 6;
5470 } else if (IsNotEscaped(character)) {
5471 escaped_length++;
5472 } else {
5473 escaped_length += 3;
5474 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005475 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005476 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005477 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005478 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005479 return Failure::OutOfMemoryException();
5480 }
5481 }
5482 }
5483 // No length change implies no change. Return original string if no change.
5484 if (escaped_length == length) {
5485 return source;
5486 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005487 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005488 { MaybeObject* maybe_o =
5489 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005490 if (!maybe_o->ToObject(&o)) return maybe_o;
5491 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005492 String* destination = String::cast(o);
5493 int dest_position = 0;
5494
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005495 Access<StringInputBuffer> buffer(
5496 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005497 buffer->Rewind();
5498 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005499 uint16_t chr = buffer->GetNext();
5500 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005501 destination->Set(dest_position, '%');
5502 destination->Set(dest_position+1, 'u');
5503 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5504 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5505 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5506 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005507 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005508 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005509 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005510 dest_position++;
5511 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005512 destination->Set(dest_position, '%');
5513 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5514 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005515 dest_position += 3;
5516 }
5517 }
5518 return destination;
5519}
5520
5521
5522static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5523 static const signed char kHexValue['g'] = {
5524 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5525 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5526 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5527 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5528 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5529 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5530 -1, 10, 11, 12, 13, 14, 15 };
5531
5532 if (character1 > 'f') return -1;
5533 int hi = kHexValue[character1];
5534 if (hi == -1) return -1;
5535 if (character2 > 'f') return -1;
5536 int lo = kHexValue[character2];
5537 if (lo == -1) return -1;
5538 return (hi << 4) + lo;
5539}
5540
5541
ager@chromium.org870a0b62008-11-04 11:43:05 +00005542static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005543 int i,
5544 int length,
5545 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005546 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005547 int32_t hi = 0;
5548 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005549 if (character == '%' &&
5550 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005551 source->Get(i + 1) == 'u' &&
5552 (hi = TwoDigitHex(source->Get(i + 2),
5553 source->Get(i + 3))) != -1 &&
5554 (lo = TwoDigitHex(source->Get(i + 4),
5555 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005556 *step = 6;
5557 return (hi << 8) + lo;
5558 } else if (character == '%' &&
5559 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005560 (lo = TwoDigitHex(source->Get(i + 1),
5561 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005562 *step = 3;
5563 return lo;
5564 } else {
5565 *step = 1;
5566 return character;
5567 }
5568}
5569
5570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005571RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005572 NoHandleAllocation ha;
5573 ASSERT(args.length() == 1);
5574 CONVERT_CHECKED(String, source, args[0]);
5575
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005576 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005577
5578 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005579 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005580
5581 int unescaped_length = 0;
5582 for (int i = 0; i < length; unescaped_length++) {
5583 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005584 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005585 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005586 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005587 i += step;
5588 }
5589
5590 // No length change implies no change. Return original string if no change.
5591 if (unescaped_length == length)
5592 return source;
5593
lrn@chromium.org303ada72010-10-27 09:33:13 +00005594 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005595 { MaybeObject* maybe_o =
5596 ascii ?
5597 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5598 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005599 if (!maybe_o->ToObject(&o)) return maybe_o;
5600 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005601 String* destination = String::cast(o);
5602
5603 int dest_position = 0;
5604 for (int i = 0; i < length; dest_position++) {
5605 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005606 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005607 i += step;
5608 }
5609 return destination;
5610}
5611
5612
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005613static const unsigned int kQuoteTableLength = 128u;
5614
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005615static const int kJsonQuotesCharactersPerEntry = 8;
5616static const char* const JsonQuotes =
5617 "\\u0000 \\u0001 \\u0002 \\u0003 "
5618 "\\u0004 \\u0005 \\u0006 \\u0007 "
5619 "\\b \\t \\n \\u000b "
5620 "\\f \\r \\u000e \\u000f "
5621 "\\u0010 \\u0011 \\u0012 \\u0013 "
5622 "\\u0014 \\u0015 \\u0016 \\u0017 "
5623 "\\u0018 \\u0019 \\u001a \\u001b "
5624 "\\u001c \\u001d \\u001e \\u001f "
5625 " ! \\\" # "
5626 "$ % & ' "
5627 "( ) * + "
5628 ", - . / "
5629 "0 1 2 3 "
5630 "4 5 6 7 "
5631 "8 9 : ; "
5632 "< = > ? "
5633 "@ A B C "
5634 "D E F G "
5635 "H I J K "
5636 "L M N O "
5637 "P Q R S "
5638 "T U V W "
5639 "X Y Z [ "
5640 "\\\\ ] ^ _ "
5641 "` a b c "
5642 "d e f g "
5643 "h i j k "
5644 "l m n o "
5645 "p q r s "
5646 "t u v w "
5647 "x y z { "
5648 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005649
5650
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005651// For a string that is less than 32k characters it should always be
5652// possible to allocate it in new space.
5653static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5654
5655
5656// Doing JSON quoting cannot make the string more than this many times larger.
5657static const int kJsonQuoteWorstCaseBlowup = 6;
5658
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005659static const int kSpaceForQuotesAndComma = 3;
5660static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005661
5662// Covers the entire ASCII range (all other characters are unchanged by JSON
5663// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005664static const byte JsonQuoteLengths[kQuoteTableLength] = {
5665 6, 6, 6, 6, 6, 6, 6, 6,
5666 2, 2, 2, 6, 2, 2, 6, 6,
5667 6, 6, 6, 6, 6, 6, 6, 6,
5668 6, 6, 6, 6, 6, 6, 6, 6,
5669 1, 1, 2, 1, 1, 1, 1, 1,
5670 1, 1, 1, 1, 1, 1, 1, 1,
5671 1, 1, 1, 1, 1, 1, 1, 1,
5672 1, 1, 1, 1, 1, 1, 1, 1,
5673 1, 1, 1, 1, 1, 1, 1, 1,
5674 1, 1, 1, 1, 1, 1, 1, 1,
5675 1, 1, 1, 1, 1, 1, 1, 1,
5676 1, 1, 1, 1, 2, 1, 1, 1,
5677 1, 1, 1, 1, 1, 1, 1, 1,
5678 1, 1, 1, 1, 1, 1, 1, 1,
5679 1, 1, 1, 1, 1, 1, 1, 1,
5680 1, 1, 1, 1, 1, 1, 1, 1,
5681};
5682
5683
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005684template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005685MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005686
5687
5688template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005689MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5690 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005691}
5692
5693
5694template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005695MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5696 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005697}
5698
5699
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005700template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005701static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5702 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005703 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005704 const Char* read_cursor = characters.start();
5705 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005706 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005707 int quoted_length = kSpaceForQuotes;
5708 while (read_cursor < end) {
5709 Char c = *(read_cursor++);
5710 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5711 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005712 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005713 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005714 }
5715 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005716 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5717 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005718 Object* new_object;
5719 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005720 return new_alloc;
5721 }
5722 StringType* new_string = StringType::cast(new_object);
5723
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005724 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005725 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005726 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005727 *(write_cursor++) = '"';
5728
5729 read_cursor = characters.start();
5730 while (read_cursor < end) {
5731 Char c = *(read_cursor++);
5732 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5733 *(write_cursor++) = c;
5734 } else {
5735 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5736 const char* replacement = JsonQuotes +
5737 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5738 for (int i = 0; i < len; i++) {
5739 *write_cursor++ = *replacement++;
5740 }
5741 }
5742 }
5743 *(write_cursor++) = '"';
5744 return new_string;
5745}
5746
5747
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005748template <typename SinkChar, typename SourceChar>
5749static inline SinkChar* WriteQuoteJsonString(
5750 Isolate* isolate,
5751 SinkChar* write_cursor,
5752 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005753 // SinkChar is only char if SourceChar is guaranteed to be char.
5754 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005755 const SourceChar* read_cursor = characters.start();
5756 const SourceChar* end = read_cursor + characters.length();
5757 *(write_cursor++) = '"';
5758 while (read_cursor < end) {
5759 SourceChar c = *(read_cursor++);
5760 if (sizeof(SourceChar) > 1u &&
5761 static_cast<unsigned>(c) >= kQuoteTableLength) {
5762 *(write_cursor++) = static_cast<SinkChar>(c);
5763 } else {
5764 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5765 const char* replacement = JsonQuotes +
5766 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5767 write_cursor[0] = replacement[0];
5768 if (len > 1) {
5769 write_cursor[1] = replacement[1];
5770 if (len > 2) {
5771 ASSERT(len == 6);
5772 write_cursor[2] = replacement[2];
5773 write_cursor[3] = replacement[3];
5774 write_cursor[4] = replacement[4];
5775 write_cursor[5] = replacement[5];
5776 }
5777 }
5778 write_cursor += len;
5779 }
5780 }
5781 *(write_cursor++) = '"';
5782 return write_cursor;
5783}
5784
5785
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005786template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005787static MaybeObject* QuoteJsonString(Isolate* isolate,
5788 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005789 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005790 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005791 int worst_case_length =
5792 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005793 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005794 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005795 }
5796
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005797 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5798 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005799 Object* new_object;
5800 if (!new_alloc->ToObject(&new_object)) {
5801 return new_alloc;
5802 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005803 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005804 // Even if our string is small enough to fit in new space we still have to
5805 // handle it being allocated in old space as may happen in the third
5806 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5807 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005808 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005809 }
5810 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005811 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005812
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005813 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005814 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005815 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005816 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5817 write_cursor,
5818 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005819 int final_length = static_cast<int>(
5820 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005821 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005822 isolate->heap()->new_space()->
5823 template ShrinkStringAtAllocationBoundary<StringType>(
5824 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005825 return new_string;
5826}
5827
5828
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005829RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005830 NoHandleAllocation ha;
5831 CONVERT_CHECKED(String, str, args[0]);
5832 if (!str->IsFlat()) {
5833 MaybeObject* try_flatten = str->TryFlatten();
5834 Object* flat;
5835 if (!try_flatten->ToObject(&flat)) {
5836 return try_flatten;
5837 }
5838 str = String::cast(flat);
5839 ASSERT(str->IsFlat());
5840 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005841 String::FlatContent flat = str->GetFlatContent();
5842 ASSERT(flat.IsFlat());
5843 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005844 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005845 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005846 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005847 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005848 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005849 }
5850}
5851
5852
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005853RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005854 NoHandleAllocation ha;
5855 CONVERT_CHECKED(String, str, args[0]);
5856 if (!str->IsFlat()) {
5857 MaybeObject* try_flatten = str->TryFlatten();
5858 Object* flat;
5859 if (!try_flatten->ToObject(&flat)) {
5860 return try_flatten;
5861 }
5862 str = String::cast(flat);
5863 ASSERT(str->IsFlat());
5864 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005865 String::FlatContent flat = str->GetFlatContent();
5866 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005867 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005868 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005869 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005870 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005871 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005872 }
5873}
5874
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005875
5876template <typename Char, typename StringType>
5877static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5878 FixedArray* array,
5879 int worst_case_length) {
5880 int length = array->length();
5881
5882 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5883 worst_case_length);
5884 Object* new_object;
5885 if (!new_alloc->ToObject(&new_object)) {
5886 return new_alloc;
5887 }
5888 if (!isolate->heap()->new_space()->Contains(new_object)) {
5889 // Even if our string is small enough to fit in new space we still have to
5890 // handle it being allocated in old space as may happen in the third
5891 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5892 // CEntryStub::GenerateCore.
5893 return isolate->heap()->undefined_value();
5894 }
5895 AssertNoAllocation no_gc;
5896 StringType* new_string = StringType::cast(new_object);
5897 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5898
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005899 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005900 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005901 *(write_cursor++) = '[';
5902 for (int i = 0; i < length; i++) {
5903 if (i != 0) *(write_cursor++) = ',';
5904 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005905 String::FlatContent content = str->GetFlatContent();
5906 ASSERT(content.IsFlat());
5907 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005908 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5909 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005910 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005911 } else {
5912 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5913 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005914 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005915 }
5916 }
5917 *(write_cursor++) = ']';
5918
5919 int final_length = static_cast<int>(
5920 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005921 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005922 isolate->heap()->new_space()->
5923 template ShrinkStringAtAllocationBoundary<StringType>(
5924 new_string, final_length);
5925 return new_string;
5926}
5927
5928
5929RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5930 NoHandleAllocation ha;
5931 ASSERT(args.length() == 1);
5932 CONVERT_CHECKED(JSArray, array, args[0]);
5933
5934 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5935 FixedArray* elements = FixedArray::cast(array->elements());
5936 int n = elements->length();
5937 bool ascii = true;
5938 int total_length = 0;
5939
5940 for (int i = 0; i < n; i++) {
5941 Object* elt = elements->get(i);
5942 if (!elt->IsString()) return isolate->heap()->undefined_value();
5943 String* element = String::cast(elt);
5944 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5945 total_length += element->length();
5946 if (ascii && element->IsTwoByteRepresentation()) {
5947 ascii = false;
5948 }
5949 }
5950
5951 int worst_case_length =
5952 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5953 + total_length * kJsonQuoteWorstCaseBlowup;
5954
5955 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5956 return isolate->heap()->undefined_value();
5957 }
5958
5959 if (ascii) {
5960 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5961 elements,
5962 worst_case_length);
5963 } else {
5964 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5965 elements,
5966 worst_case_length);
5967 }
5968}
5969
5970
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005971RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005972 NoHandleAllocation ha;
5973
5974 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005975 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005976
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005977 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005978
lrn@chromium.org25156de2010-04-06 13:10:27 +00005979 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005980 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005981 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982}
5983
5984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005985RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005986 NoHandleAllocation ha;
5987 CONVERT_CHECKED(String, str, args[0]);
5988
5989 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005990 double value = StringToDouble(isolate->unicode_cache(),
5991 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005992
5993 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005994 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995}
5996
5997
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005998template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005999MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006000 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00006001 String* s,
6002 int length,
6003 int input_string_length,
6004 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006005 // We try this twice, once with the assumption that the result is no longer
6006 // than the input and, if that assumption breaks, again with the exact
6007 // length. This may not be pretty, but it is nicer than what was here before
6008 // and I hereby claim my vaffel-is.
6009 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006010 // Allocate the resulting string.
6011 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006012 // NOTE: This assumes that the upper/lower case of an ASCII
6013 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006014 // might break in the future if we implement more context and locale
6015 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006016 Object* o;
6017 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006018 ? isolate->heap()->AllocateRawAsciiString(length)
6019 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006020 if (!maybe_o->ToObject(&o)) return maybe_o;
6021 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006022 String* result = String::cast(o);
6023 bool has_changed_character = false;
6024
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006025 // Convert all characters to upper case, assuming that they will fit
6026 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006027 Access<StringInputBuffer> buffer(
6028 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006029 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006030 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006031 // We can assume that the string is not empty
6032 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006033 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006034 bool has_next = buffer->has_more();
6035 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006036 int char_length = mapping->get(current, next, chars);
6037 if (char_length == 0) {
6038 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006039 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040 i++;
6041 } else if (char_length == 1) {
6042 // Common case: converting the letter resulted in one character.
6043 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006044 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006045 has_changed_character = true;
6046 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006047 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006048 // We've assumed that the result would be as long as the
6049 // input but here is a character that converts to several
6050 // characters. No matter, we calculate the exact length
6051 // of the result and try the whole thing again.
6052 //
6053 // Note that this leaves room for optimization. We could just
6054 // memcpy what we already have to the result string. Also,
6055 // the result string is the last object allocated we could
6056 // "realloc" it and probably, in the vast majority of cases,
6057 // extend the existing string to be able to hold the full
6058 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006059 int next_length = 0;
6060 if (has_next) {
6061 next_length = mapping->get(next, 0, chars);
6062 if (next_length == 0) next_length = 1;
6063 }
6064 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006065 while (buffer->has_more()) {
6066 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006067 // NOTE: we use 0 as the next character here because, while
6068 // the next character may affect what a character converts to,
6069 // it does not in any case affect the length of what it convert
6070 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006071 int char_length = mapping->get(current, 0, chars);
6072 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006073 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006074 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006075 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006076 return Failure::OutOfMemoryException();
6077 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006078 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006079 // Try again with the real length.
6080 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006081 } else {
6082 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006083 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006084 i++;
6085 }
6086 has_changed_character = true;
6087 }
6088 current = next;
6089 }
6090 if (has_changed_character) {
6091 return result;
6092 } else {
6093 // If we didn't actually change anything in doing the conversion
6094 // we simple return the result and let the converted string
6095 // become garbage; there is no reason to keep two identical strings
6096 // alive.
6097 return s;
6098 }
6099}
6100
6101
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006102namespace {
6103
lrn@chromium.org303ada72010-10-27 09:33:13 +00006104static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6105
6106
6107// Given a word and two range boundaries returns a word with high bit
6108// set in every byte iff the corresponding input byte was strictly in
6109// the range (m, n). All the other bits in the result are cleared.
6110// This function is only useful when it can be inlined and the
6111// boundaries are statically known.
6112// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006113// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006114static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006115 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006116 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6117 // Use strict inequalities since in edge cases the function could be
6118 // further simplified.
6119 ASSERT(0 < m && m < n && n < 0x7F);
6120 // Has high bit set in every w byte less than n.
6121 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6122 // Has high bit set in every w byte greater than m.
6123 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6124 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6125}
6126
6127
6128enum AsciiCaseConversion {
6129 ASCII_TO_LOWER,
6130 ASCII_TO_UPPER
6131};
6132
6133
6134template <AsciiCaseConversion dir>
6135struct FastAsciiConverter {
6136 static bool Convert(char* dst, char* src, int length) {
6137#ifdef DEBUG
6138 char* saved_dst = dst;
6139 char* saved_src = src;
6140#endif
6141 // We rely on the distance between upper and lower case letters
6142 // being a known power of 2.
6143 ASSERT('a' - 'A' == (1 << 5));
6144 // Boundaries for the range of input characters than require conversion.
6145 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6146 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6147 bool changed = false;
6148 char* const limit = src + length;
6149#ifdef V8_HOST_CAN_READ_UNALIGNED
6150 // Process the prefix of the input that requires no conversion one
6151 // (machine) word at a time.
6152 while (src <= limit - sizeof(uintptr_t)) {
6153 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6154 if (AsciiRangeMask(w, lo, hi) != 0) {
6155 changed = true;
6156 break;
6157 }
6158 *reinterpret_cast<uintptr_t*>(dst) = w;
6159 src += sizeof(uintptr_t);
6160 dst += sizeof(uintptr_t);
6161 }
6162 // Process the remainder of the input performing conversion when
6163 // required one word at a time.
6164 while (src <= limit - sizeof(uintptr_t)) {
6165 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6166 uintptr_t m = AsciiRangeMask(w, lo, hi);
6167 // The mask has high (7th) bit set in every byte that needs
6168 // conversion and we know that the distance between cases is
6169 // 1 << 5.
6170 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6171 src += sizeof(uintptr_t);
6172 dst += sizeof(uintptr_t);
6173 }
6174#endif
6175 // Process the last few bytes of the input (or the whole input if
6176 // unaligned access is not supported).
6177 while (src < limit) {
6178 char c = *src;
6179 if (lo < c && c < hi) {
6180 c ^= (1 << 5);
6181 changed = true;
6182 }
6183 *dst = c;
6184 ++src;
6185 ++dst;
6186 }
6187#ifdef DEBUG
6188 CheckConvert(saved_dst, saved_src, length, changed);
6189#endif
6190 return changed;
6191 }
6192
6193#ifdef DEBUG
6194 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6195 bool expected_changed = false;
6196 for (int i = 0; i < length; i++) {
6197 if (dst[i] == src[i]) continue;
6198 expected_changed = true;
6199 if (dir == ASCII_TO_LOWER) {
6200 ASSERT('A' <= src[i] && src[i] <= 'Z');
6201 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6202 } else {
6203 ASSERT(dir == ASCII_TO_UPPER);
6204 ASSERT('a' <= src[i] && src[i] <= 'z');
6205 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6206 }
6207 }
6208 ASSERT(expected_changed == changed);
6209 }
6210#endif
6211};
6212
6213
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006214struct ToLowerTraits {
6215 typedef unibrow::ToLowercase UnibrowConverter;
6216
lrn@chromium.org303ada72010-10-27 09:33:13 +00006217 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006218};
6219
6220
6221struct ToUpperTraits {
6222 typedef unibrow::ToUppercase UnibrowConverter;
6223
lrn@chromium.org303ada72010-10-27 09:33:13 +00006224 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006225};
6226
6227} // namespace
6228
6229
6230template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006231MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006232 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006233 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006234 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006235 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006236 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006237 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006238
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006239 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006240 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006241 if (length == 0) return s;
6242
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006243 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006244 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006245 // NOTE: This assumes that the upper/lower case of an ASCII
6246 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006247 // might break in the future if we implement more context and locale
6248 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006249 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006250 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006251 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006252 if (!maybe_o->ToObject(&o)) return maybe_o;
6253 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006254 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006255 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006256 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006257 return has_changed_character ? result : s;
6258 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006259
lrn@chromium.org303ada72010-10-27 09:33:13 +00006260 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006261 { MaybeObject* maybe_answer =
6262 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006263 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6264 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006265 if (answer->IsSmi()) {
6266 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006267 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006268 ConvertCaseHelper(isolate,
6269 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006270 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6271 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006272 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006273 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006274}
6275
6276
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006277RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006278 return ConvertCase<ToLowerTraits>(
6279 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006280}
6281
6282
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006283RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006284 return ConvertCase<ToUpperTraits>(
6285 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006286}
6287
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006288
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006289static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006290 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006291}
6292
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006294RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006295 NoHandleAllocation ha;
6296 ASSERT(args.length() == 3);
6297
6298 CONVERT_CHECKED(String, s, args[0]);
6299 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6300 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6301
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006302 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006303 int length = s->length();
6304
6305 int left = 0;
6306 if (trimLeft) {
6307 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6308 left++;
6309 }
6310 }
6311
6312 int right = length;
6313 if (trimRight) {
6314 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6315 right--;
6316 }
6317 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006318 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006319}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006320
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006321
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006322RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006323 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006324 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006325 CONVERT_ARG_CHECKED(String, subject, 0);
6326 CONVERT_ARG_CHECKED(String, pattern, 1);
6327 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6328
6329 int subject_length = subject->length();
6330 int pattern_length = pattern->length();
6331 RUNTIME_ASSERT(pattern_length > 0);
6332
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006333 if (limit == 0xffffffffu) {
6334 Handle<Object> cached_answer(StringSplitCache::Lookup(
6335 isolate->heap()->string_split_cache(),
6336 *subject,
6337 *pattern));
6338 if (*cached_answer != Smi::FromInt(0)) {
6339 Handle<JSArray> result =
6340 isolate->factory()->NewJSArrayWithElements(
6341 Handle<FixedArray>::cast(cached_answer));
6342 return *result;
6343 }
6344 }
6345
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006346 // The limit can be very large (0xffffffffu), but since the pattern
6347 // isn't empty, we can never create more parts than ~half the length
6348 // of the subject.
6349
6350 if (!subject->IsFlat()) FlattenString(subject);
6351
6352 static const int kMaxInitialListCapacity = 16;
6353
danno@chromium.org40cb8782011-05-25 07:58:50 +00006354 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006355
6356 // Find (up to limit) indices of separator and end-of-string in subject
6357 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6358 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006359 if (!pattern->IsFlat()) FlattenString(pattern);
6360
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006361 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006362
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006363 if (static_cast<uint32_t>(indices.length()) < limit) {
6364 indices.Add(subject_length);
6365 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006366
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006367 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006368
6369 // Create JSArray of substrings separated by separator.
6370 int part_count = indices.length();
6371
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006372 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006373 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006374 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006375 result->set_length(Smi::FromInt(part_count));
6376
6377 ASSERT(result->HasFastElements());
6378
6379 if (part_count == 1 && indices.at(0) == subject_length) {
6380 FixedArray::cast(result->elements())->set(0, *subject);
6381 return *result;
6382 }
6383
6384 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6385 int part_start = 0;
6386 for (int i = 0; i < part_count; i++) {
6387 HandleScope local_loop_handle;
6388 int part_end = indices.at(i);
6389 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006390 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006391 elements->set(i, *substring);
6392 part_start = part_end + pattern_length;
6393 }
6394
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006395 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006396 if (result->HasFastElements()) {
6397 StringSplitCache::Enter(isolate->heap(),
6398 isolate->heap()->string_split_cache(),
6399 *subject,
6400 *pattern,
6401 *elements);
6402 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006403 }
6404
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006405 return *result;
6406}
6407
6408
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006409// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006410// one-char strings in the cache. Gives up on the first char that is
6411// not in the cache and fills the remainder with smi zeros. Returns
6412// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006413static int CopyCachedAsciiCharsToArray(Heap* heap,
6414 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006415 FixedArray* elements,
6416 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006417 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006418 FixedArray* ascii_cache = heap->single_character_string_cache();
6419 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006420 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006421 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006422 for (i = 0; i < length; ++i) {
6423 Object* value = ascii_cache->get(chars[i]);
6424 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006425 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006426 }
6427 if (i < length) {
6428 ASSERT(Smi::FromInt(0) == 0);
6429 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6430 }
6431#ifdef DEBUG
6432 for (int j = 0; j < length; ++j) {
6433 Object* element = elements->get(j);
6434 ASSERT(element == Smi::FromInt(0) ||
6435 (element->IsString() && String::cast(element)->LooksValid()));
6436 }
6437#endif
6438 return i;
6439}
6440
6441
6442// Converts a String to JSArray.
6443// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006444RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006445 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006446 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006447 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006448 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006449
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006450 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006451 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006452
6453 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006454 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006455 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006456 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006457 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006458 { MaybeObject* maybe_obj =
6459 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006460 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6461 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006462 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006463 String::FlatContent content = s->GetFlatContent();
6464 if (content.IsAscii()) {
6465 Vector<const char> chars = content.ToAsciiVector();
6466 // Note, this will initialize all elements (not only the prefix)
6467 // to prevent GC from seeing partially initialized array.
6468 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6469 chars.start(),
6470 *elements,
6471 length);
6472 } else {
6473 MemsetPointer(elements->data_start(),
6474 isolate->heap()->undefined_value(),
6475 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006476 }
6477 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006478 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006479 }
6480 for (int i = position; i < length; ++i) {
6481 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6482 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006483 }
6484
6485#ifdef DEBUG
6486 for (int i = 0; i < length; ++i) {
6487 ASSERT(String::cast(elements->get(i))->length() == 1);
6488 }
6489#endif
6490
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006491 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006492}
6493
6494
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006495RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006496 NoHandleAllocation ha;
6497 ASSERT(args.length() == 1);
6498 CONVERT_CHECKED(String, value, args[0]);
6499 return value->ToObject();
6500}
6501
6502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006503bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006504 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006505 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006506 return char_length == 0;
6507}
6508
6509
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006510RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006511 NoHandleAllocation ha;
6512 ASSERT(args.length() == 1);
6513
6514 Object* number = args[0];
6515 RUNTIME_ASSERT(number->IsNumber());
6516
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006517 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006518}
6519
6520
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006521RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006522 NoHandleAllocation ha;
6523 ASSERT(args.length() == 1);
6524
6525 Object* number = args[0];
6526 RUNTIME_ASSERT(number->IsNumber());
6527
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006528 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006529}
6530
6531
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006532RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006533 NoHandleAllocation ha;
6534 ASSERT(args.length() == 1);
6535
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006536 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006537
6538 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6539 if (number > 0 && number <= Smi::kMaxValue) {
6540 return Smi::FromInt(static_cast<int>(number));
6541 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006542 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006543}
6544
6545
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006546RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006547 NoHandleAllocation ha;
6548 ASSERT(args.length() == 1);
6549
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006550 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006551
6552 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6553 if (number > 0 && number <= Smi::kMaxValue) {
6554 return Smi::FromInt(static_cast<int>(number));
6555 }
6556
6557 double double_value = DoubleToInteger(number);
6558 // Map both -0 and +0 to +0.
6559 if (double_value == 0) double_value = 0;
6560
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006561 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006562}
6563
6564
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006565RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006566 NoHandleAllocation ha;
6567 ASSERT(args.length() == 1);
6568
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006569 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006570 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006571}
6572
6573
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006574RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006575 NoHandleAllocation ha;
6576 ASSERT(args.length() == 1);
6577
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006578 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006579
6580 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6581 if (number > 0 && number <= Smi::kMaxValue) {
6582 return Smi::FromInt(static_cast<int>(number));
6583 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006584 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006585}
6586
6587
ager@chromium.org870a0b62008-11-04 11:43:05 +00006588// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6589// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006590RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006591 NoHandleAllocation ha;
6592 ASSERT(args.length() == 1);
6593
6594 Object* obj = args[0];
6595 if (obj->IsSmi()) {
6596 return obj;
6597 }
6598 if (obj->IsHeapNumber()) {
6599 double value = HeapNumber::cast(obj)->value();
6600 int int_value = FastD2I(value);
6601 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6602 return Smi::FromInt(int_value);
6603 }
6604 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006605 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006606}
6607
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006608
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006609RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006610 NoHandleAllocation ha;
6611 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006612 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006613}
6614
6615
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006616RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006617 NoHandleAllocation ha;
6618 ASSERT(args.length() == 2);
6619
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006620 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6621 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006622 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006623}
6624
6625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006626RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006627 NoHandleAllocation ha;
6628 ASSERT(args.length() == 2);
6629
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006630 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6631 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006632 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633}
6634
6635
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006636RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006637 NoHandleAllocation ha;
6638 ASSERT(args.length() == 2);
6639
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006640 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6641 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006642 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006643}
6644
6645
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006646RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006647 NoHandleAllocation ha;
6648 ASSERT(args.length() == 1);
6649
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006650 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006651 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652}
6653
6654
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006655RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006656 NoHandleAllocation ha;
6657 ASSERT(args.length() == 0);
6658
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006659 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006660}
6661
6662
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006663RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006664 NoHandleAllocation ha;
6665 ASSERT(args.length() == 2);
6666
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006667 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6668 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006669 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006670}
6671
6672
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006673RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006674 NoHandleAllocation ha;
6675 ASSERT(args.length() == 2);
6676
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006677 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6678 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006679
ager@chromium.org3811b432009-10-28 14:53:37 +00006680 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006681 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006682 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006683}
6684
6685
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006686RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006687 NoHandleAllocation ha;
6688 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006689 CONVERT_CHECKED(String, str1, args[0]);
6690 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006691 isolate->counters()->string_add_runtime()->Increment();
6692 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006693}
6694
6695
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006696template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006697static inline void StringBuilderConcatHelper(String* special,
6698 sinkchar* sink,
6699 FixedArray* fixed_array,
6700 int array_length) {
6701 int position = 0;
6702 for (int i = 0; i < array_length; i++) {
6703 Object* element = fixed_array->get(i);
6704 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006705 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006706 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006707 int pos;
6708 int len;
6709 if (encoded_slice > 0) {
6710 // Position and length encoded in one smi.
6711 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6712 len = StringBuilderSubstringLength::decode(encoded_slice);
6713 } else {
6714 // Position and length encoded in two smis.
6715 Object* obj = fixed_array->get(++i);
6716 ASSERT(obj->IsSmi());
6717 pos = Smi::cast(obj)->value();
6718 len = -encoded_slice;
6719 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006720 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006721 sink + position,
6722 pos,
6723 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006724 position += len;
6725 } else {
6726 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006727 int element_length = string->length();
6728 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006729 position += element_length;
6730 }
6731 }
6732}
6733
6734
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006735RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006736 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006737 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006738 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006739 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006740 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006741 return Failure::OutOfMemoryException();
6742 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006743 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006744 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006745
6746 // This assumption is used by the slice encoding in one or two smis.
6747 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6748
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006749 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006750 if (maybe_result->IsFailure()) return maybe_result;
6751
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006752 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006754 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006755 }
6756 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006757 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006758 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006759 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006760
6761 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006762 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006763 } else if (array_length == 1) {
6764 Object* first = fixed_array->get(0);
6765 if (first->IsString()) return first;
6766 }
6767
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006768 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006769 int position = 0;
6770 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006771 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006772 Object* elt = fixed_array->get(i);
6773 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006774 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006775 int smi_value = Smi::cast(elt)->value();
6776 int pos;
6777 int len;
6778 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006779 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006780 pos = StringBuilderSubstringPosition::decode(smi_value);
6781 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006782 } else {
6783 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006784 len = -smi_value;
6785 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006786 i++;
6787 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006788 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006789 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006790 Object* next_smi = fixed_array->get(i);
6791 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006792 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006793 }
6794 pos = Smi::cast(next_smi)->value();
6795 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006796 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006797 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006798 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006799 ASSERT(pos >= 0);
6800 ASSERT(len >= 0);
6801 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006802 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006803 }
6804 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006805 } else if (elt->IsString()) {
6806 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006807 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006808 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006809 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006810 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006811 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006812 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006813 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006814 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006815 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006816 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006817 return Failure::OutOfMemoryException();
6818 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006819 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006820 }
6821
6822 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006823 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006824
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006825 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006826 { MaybeObject* maybe_object =
6827 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006828 if (!maybe_object->ToObject(&object)) return maybe_object;
6829 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006830 SeqAsciiString* answer = SeqAsciiString::cast(object);
6831 StringBuilderConcatHelper(special,
6832 answer->GetChars(),
6833 fixed_array,
6834 array_length);
6835 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006836 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006837 { MaybeObject* maybe_object =
6838 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006839 if (!maybe_object->ToObject(&object)) return maybe_object;
6840 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006841 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6842 StringBuilderConcatHelper(special,
6843 answer->GetChars(),
6844 fixed_array,
6845 array_length);
6846 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006847 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006848}
6849
6850
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006851RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006852 NoHandleAllocation ha;
6853 ASSERT(args.length() == 3);
6854 CONVERT_CHECKED(JSArray, array, args[0]);
6855 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006856 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006857 return Failure::OutOfMemoryException();
6858 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006859 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006860 CONVERT_CHECKED(String, separator, args[2]);
6861
6862 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006863 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006864 }
6865 FixedArray* fixed_array = FixedArray::cast(array->elements());
6866 if (fixed_array->length() < array_length) {
6867 array_length = fixed_array->length();
6868 }
6869
6870 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006871 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006872 } else if (array_length == 1) {
6873 Object* first = fixed_array->get(0);
6874 if (first->IsString()) return first;
6875 }
6876
6877 int separator_length = separator->length();
6878 int max_nof_separators =
6879 (String::kMaxLength + separator_length - 1) / separator_length;
6880 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006881 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006882 return Failure::OutOfMemoryException();
6883 }
6884 int length = (array_length - 1) * separator_length;
6885 for (int i = 0; i < array_length; i++) {
6886 Object* element_obj = fixed_array->get(i);
6887 if (!element_obj->IsString()) {
6888 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006889 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006890 }
6891 String* element = String::cast(element_obj);
6892 int increment = element->length();
6893 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006894 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006895 return Failure::OutOfMemoryException();
6896 }
6897 length += increment;
6898 }
6899
6900 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006901 { MaybeObject* maybe_object =
6902 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006903 if (!maybe_object->ToObject(&object)) return maybe_object;
6904 }
6905 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6906
6907 uc16* sink = answer->GetChars();
6908#ifdef DEBUG
6909 uc16* end = sink + length;
6910#endif
6911
6912 String* first = String::cast(fixed_array->get(0));
6913 int first_length = first->length();
6914 String::WriteToFlat(first, sink, 0, first_length);
6915 sink += first_length;
6916
6917 for (int i = 1; i < array_length; i++) {
6918 ASSERT(sink + separator_length <= end);
6919 String::WriteToFlat(separator, sink, 0, separator_length);
6920 sink += separator_length;
6921
6922 String* element = String::cast(fixed_array->get(i));
6923 int element_length = element->length();
6924 ASSERT(sink + element_length <= end);
6925 String::WriteToFlat(element, sink, 0, element_length);
6926 sink += element_length;
6927 }
6928 ASSERT(sink == end);
6929
6930 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6931 return answer;
6932}
6933
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006934template <typename Char>
6935static void JoinSparseArrayWithSeparator(FixedArray* elements,
6936 int elements_length,
6937 uint32_t array_length,
6938 String* separator,
6939 Vector<Char> buffer) {
6940 int previous_separator_position = 0;
6941 int separator_length = separator->length();
6942 int cursor = 0;
6943 for (int i = 0; i < elements_length; i += 2) {
6944 int position = NumberToInt32(elements->get(i));
6945 String* string = String::cast(elements->get(i + 1));
6946 int string_length = string->length();
6947 if (string->length() > 0) {
6948 while (previous_separator_position < position) {
6949 String::WriteToFlat<Char>(separator, &buffer[cursor],
6950 0, separator_length);
6951 cursor += separator_length;
6952 previous_separator_position++;
6953 }
6954 String::WriteToFlat<Char>(string, &buffer[cursor],
6955 0, string_length);
6956 cursor += string->length();
6957 }
6958 }
6959 if (separator_length > 0) {
6960 // Array length must be representable as a signed 32-bit number,
6961 // otherwise the total string length would have been too large.
6962 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6963 int last_array_index = static_cast<int>(array_length - 1);
6964 while (previous_separator_position < last_array_index) {
6965 String::WriteToFlat<Char>(separator, &buffer[cursor],
6966 0, separator_length);
6967 cursor += separator_length;
6968 previous_separator_position++;
6969 }
6970 }
6971 ASSERT(cursor <= buffer.length());
6972}
6973
6974
6975RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6976 NoHandleAllocation ha;
6977 ASSERT(args.length() == 3);
6978 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006979 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6980 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006981 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6982 CONVERT_CHECKED(String, separator, args[2]);
6983 // elements_array is fast-mode JSarray of alternating positions
6984 // (increasing order) and strings.
6985 // array_length is length of original array (used to add separators);
6986 // separator is string to put between elements. Assumed to be non-empty.
6987
6988 // Find total length of join result.
6989 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006990 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006991 int max_string_length;
6992 if (is_ascii) {
6993 max_string_length = SeqAsciiString::kMaxLength;
6994 } else {
6995 max_string_length = SeqTwoByteString::kMaxLength;
6996 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006997 bool overflow = false;
6998 CONVERT_NUMBER_CHECKED(int, elements_length,
6999 Int32, elements_array->length());
7000 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
7001 FixedArray* elements = FixedArray::cast(elements_array->elements());
7002 for (int i = 0; i < elements_length; i += 2) {
7003 RUNTIME_ASSERT(elements->get(i)->IsNumber());
7004 CONVERT_CHECKED(String, string, elements->get(i + 1));
7005 int length = string->length();
7006 if (is_ascii && !string->IsAsciiRepresentation()) {
7007 is_ascii = false;
7008 max_string_length = SeqTwoByteString::kMaxLength;
7009 }
7010 if (length > max_string_length ||
7011 max_string_length - length < string_length) {
7012 overflow = true;
7013 break;
7014 }
7015 string_length += length;
7016 }
7017 int separator_length = separator->length();
7018 if (!overflow && separator_length > 0) {
7019 if (array_length <= 0x7fffffffu) {
7020 int separator_count = static_cast<int>(array_length) - 1;
7021 int remaining_length = max_string_length - string_length;
7022 if ((remaining_length / separator_length) >= separator_count) {
7023 string_length += separator_length * (array_length - 1);
7024 } else {
7025 // Not room for the separators within the maximal string length.
7026 overflow = true;
7027 }
7028 } else {
7029 // Nonempty separator and at least 2^31-1 separators necessary
7030 // means that the string is too large to create.
7031 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7032 overflow = true;
7033 }
7034 }
7035 if (overflow) {
7036 // Throw OutOfMemory exception for creating too large a string.
7037 V8::FatalProcessOutOfMemory("Array join result too large.");
7038 }
7039
7040 if (is_ascii) {
7041 MaybeObject* result_allocation =
7042 isolate->heap()->AllocateRawAsciiString(string_length);
7043 if (result_allocation->IsFailure()) return result_allocation;
7044 SeqAsciiString* result_string =
7045 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
7046 JoinSparseArrayWithSeparator<char>(elements,
7047 elements_length,
7048 array_length,
7049 separator,
7050 Vector<char>(result_string->GetChars(),
7051 string_length));
7052 return result_string;
7053 } else {
7054 MaybeObject* result_allocation =
7055 isolate->heap()->AllocateRawTwoByteString(string_length);
7056 if (result_allocation->IsFailure()) return result_allocation;
7057 SeqTwoByteString* result_string =
7058 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7059 JoinSparseArrayWithSeparator<uc16>(elements,
7060 elements_length,
7061 array_length,
7062 separator,
7063 Vector<uc16>(result_string->GetChars(),
7064 string_length));
7065 return result_string;
7066 }
7067}
7068
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007070RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007071 NoHandleAllocation ha;
7072 ASSERT(args.length() == 2);
7073
7074 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7075 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007076 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007077}
7078
7079
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007080RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007081 NoHandleAllocation ha;
7082 ASSERT(args.length() == 2);
7083
7084 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7085 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007086 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007087}
7088
7089
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007090RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007091 NoHandleAllocation ha;
7092 ASSERT(args.length() == 2);
7093
7094 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7095 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007096 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007097}
7098
7099
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007100RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007101 NoHandleAllocation ha;
7102 ASSERT(args.length() == 1);
7103
7104 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007105 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007106}
7107
7108
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007109RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007110 NoHandleAllocation ha;
7111 ASSERT(args.length() == 2);
7112
7113 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7114 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007115 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007116}
7117
7118
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007119RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007120 NoHandleAllocation ha;
7121 ASSERT(args.length() == 2);
7122
7123 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7124 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007125 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007126}
7127
7128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007129RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007130 NoHandleAllocation ha;
7131 ASSERT(args.length() == 2);
7132
7133 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7134 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007135 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007136}
7137
7138
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007139RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007140 NoHandleAllocation ha;
7141 ASSERT(args.length() == 2);
7142
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007143 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7144 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007145 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7146 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7147 if (x == y) return Smi::FromInt(EQUAL);
7148 Object* result;
7149 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7150 result = Smi::FromInt(EQUAL);
7151 } else {
7152 result = Smi::FromInt(NOT_EQUAL);
7153 }
7154 return result;
7155}
7156
7157
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007158RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007159 NoHandleAllocation ha;
7160 ASSERT(args.length() == 2);
7161
7162 CONVERT_CHECKED(String, x, args[0]);
7163 CONVERT_CHECKED(String, y, args[1]);
7164
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007165 bool not_equal = !x->Equals(y);
7166 // This is slightly convoluted because the value that signifies
7167 // equality is 0 and inequality is 1 so we have to negate the result
7168 // from String::Equals.
7169 ASSERT(not_equal == 0 || not_equal == 1);
7170 STATIC_CHECK(EQUAL == 0);
7171 STATIC_CHECK(NOT_EQUAL == 1);
7172 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007173}
7174
7175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007176RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007177 NoHandleAllocation ha;
7178 ASSERT(args.length() == 3);
7179
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007180 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7181 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007182 if (isnan(x) || isnan(y)) return args[2];
7183 if (x == y) return Smi::FromInt(EQUAL);
7184 if (isless(x, y)) return Smi::FromInt(LESS);
7185 return Smi::FromInt(GREATER);
7186}
7187
7188
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007189// Compare two Smis as if they were converted to strings and then
7190// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007191RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007192 NoHandleAllocation ha;
7193 ASSERT(args.length() == 2);
7194
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007195 // Extract the integer values from the Smis.
7196 CONVERT_CHECKED(Smi, x, args[0]);
7197 CONVERT_CHECKED(Smi, y, args[1]);
7198 int x_value = x->value();
7199 int y_value = y->value();
7200
7201 // If the integers are equal so are the string representations.
7202 if (x_value == y_value) return Smi::FromInt(EQUAL);
7203
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007204 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007205 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007206 if (x_value == 0 || y_value == 0)
7207 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007208
ager@chromium.org32912102009-01-16 10:38:43 +00007209 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007210 // smallest because the char code of '-' is less than the char code
7211 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007212
7213 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7214 // architectures using 32-bit Smis.
7215 uint32_t x_scaled = x_value;
7216 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007217 if (x_value < 0 || y_value < 0) {
7218 if (y_value >= 0) return Smi::FromInt(LESS);
7219 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007220 x_scaled = -x_value;
7221 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007222 }
7223
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007224 static const uint32_t kPowersOf10[] = {
7225 1, 10, 100, 1000, 10*1000, 100*1000,
7226 1000*1000, 10*1000*1000, 100*1000*1000,
7227 1000*1000*1000
7228 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007229
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007230 // If the integers have the same number of decimal digits they can be
7231 // compared directly as the numeric order is the same as the
7232 // lexicographic order. If one integer has fewer digits, it is scaled
7233 // by some power of 10 to have the same number of digits as the longer
7234 // integer. If the scaled integers are equal it means the shorter
7235 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007236
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007237 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7238 int x_log2 = IntegerLog2(x_scaled);
7239 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7240 x_log10 -= x_scaled < kPowersOf10[x_log10];
7241
7242 int y_log2 = IntegerLog2(y_scaled);
7243 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7244 y_log10 -= y_scaled < kPowersOf10[y_log10];
7245
7246 int tie = EQUAL;
7247
7248 if (x_log10 < y_log10) {
7249 // X has fewer digits. We would like to simply scale up X but that
7250 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7251 // be scaled up to 9_000_000_000. So we scale up by the next
7252 // smallest power and scale down Y to drop one digit. It is OK to
7253 // drop one digit from the longer integer since the final digit is
7254 // past the length of the shorter integer.
7255 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7256 y_scaled /= 10;
7257 tie = LESS;
7258 } else if (y_log10 < x_log10) {
7259 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7260 x_scaled /= 10;
7261 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007262 }
7263
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007264 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7265 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7266 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007267}
7268
7269
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007270static Object* StringInputBufferCompare(RuntimeState* state,
7271 String* x,
7272 String* y) {
7273 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7274 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007275 bufx.Reset(x);
7276 bufy.Reset(y);
7277 while (bufx.has_more() && bufy.has_more()) {
7278 int d = bufx.GetNext() - bufy.GetNext();
7279 if (d < 0) return Smi::FromInt(LESS);
7280 else if (d > 0) return Smi::FromInt(GREATER);
7281 }
7282
7283 // x is (non-trivial) prefix of y:
7284 if (bufy.has_more()) return Smi::FromInt(LESS);
7285 // y is prefix of x:
7286 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7287}
7288
7289
7290static Object* FlatStringCompare(String* x, String* y) {
7291 ASSERT(x->IsFlat());
7292 ASSERT(y->IsFlat());
7293 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7294 int prefix_length = x->length();
7295 if (y->length() < prefix_length) {
7296 prefix_length = y->length();
7297 equal_prefix_result = Smi::FromInt(GREATER);
7298 } else if (y->length() > prefix_length) {
7299 equal_prefix_result = Smi::FromInt(LESS);
7300 }
7301 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007302 String::FlatContent x_content = x->GetFlatContent();
7303 String::FlatContent y_content = y->GetFlatContent();
7304 if (x_content.IsAscii()) {
7305 Vector<const char> x_chars = x_content.ToAsciiVector();
7306 if (y_content.IsAscii()) {
7307 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007308 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007309 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007310 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007311 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7312 }
7313 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007314 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7315 if (y_content.IsAscii()) {
7316 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007317 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7318 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007319 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007320 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7321 }
7322 }
7323 Object* result;
7324 if (r == 0) {
7325 result = equal_prefix_result;
7326 } else {
7327 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7328 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007329 ASSERT(result ==
7330 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007331 return result;
7332}
7333
7334
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007335RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007336 NoHandleAllocation ha;
7337 ASSERT(args.length() == 2);
7338
7339 CONVERT_CHECKED(String, x, args[0]);
7340 CONVERT_CHECKED(String, y, args[1]);
7341
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007342 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007343
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007344 // A few fast case tests before we flatten.
7345 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007346 if (y->length() == 0) {
7347 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007348 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007349 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007350 return Smi::FromInt(LESS);
7351 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007352
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007353 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007354 if (d < 0) return Smi::FromInt(LESS);
7355 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007356
lrn@chromium.org303ada72010-10-27 09:33:13 +00007357 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007358 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007359 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7360 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007361 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007362 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7363 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007364
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007365 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007366 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007367}
7368
7369
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007370RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007371 NoHandleAllocation ha;
7372 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007373 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007375 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007376 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377}
7378
7379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007380RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007381 NoHandleAllocation ha;
7382 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007383 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007385 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007386 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387}
7388
7389
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007390RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007391 NoHandleAllocation ha;
7392 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007393 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007394
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007395 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007396 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397}
7398
7399
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007400static const double kPiDividedBy4 = 0.78539816339744830962;
7401
7402
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007403RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007404 NoHandleAllocation ha;
7405 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007406 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007407
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007408 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7409 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007410 double result;
7411 if (isinf(x) && isinf(y)) {
7412 // Make sure that the result in case of two infinite arguments
7413 // is a multiple of Pi / 4. The sign of the result is determined
7414 // by the first argument (x) and the sign of the second argument
7415 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007416 int multiplier = (x < 0) ? -1 : 1;
7417 if (y < 0) multiplier *= 3;
7418 result = multiplier * kPiDividedBy4;
7419 } else {
7420 result = atan2(x, y);
7421 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007422 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007423}
7424
7425
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007426RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007427 NoHandleAllocation ha;
7428 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007429 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007430
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007431 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007432 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007433}
7434
7435
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007436RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007437 NoHandleAllocation ha;
7438 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007439 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007440
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007441 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007442 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007443}
7444
7445
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007446RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007447 NoHandleAllocation ha;
7448 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007449 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007450
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007451 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007452 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007453}
7454
7455
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007456RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007457 NoHandleAllocation ha;
7458 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007459 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007460
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007461 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007462 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007463}
7464
7465
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007466RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007467 NoHandleAllocation ha;
7468 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007469 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007470
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007471 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007472 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007473}
7474
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007475// Slow version of Math.pow. We check for fast paths for special cases.
7476// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007477RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007478 NoHandleAllocation ha;
7479 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007480 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007481
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007482 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007483
7484 // If the second argument is a smi, it is much faster to call the
7485 // custom powi() function than the generic pow().
7486 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007487 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007488 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007489 }
7490
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007491 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007492 int y_int = static_cast<int>(y);
7493 double result;
7494 if (y == y_int) {
7495 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7496 } else if (y == 0.5) {
7497 result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0.
7498 } else if (y == -0.5) {
7499 result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0.
7500 } else {
7501 result = power_double_double(x, y);
7502 }
7503 if (isnan(result)) return isolate->heap()->nan_value();
7504 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007505}
7506
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007507// 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 +00007508// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007509RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007510 NoHandleAllocation ha;
7511 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007512 isolate->counters()->math_pow()->Increment();
7513
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007514 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7515 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007516 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007517 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007518 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007519 double result = power_double_double(x, y);
7520 if (isnan(result)) return isolate->heap()->nan_value();
7521 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007522 }
7523}
7524
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007525
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007526RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007527 NoHandleAllocation ha;
7528 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007529 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007530
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007531 if (!args[0]->IsHeapNumber()) {
7532 // Must be smi. Return the argument unchanged for all the other types
7533 // to make fuzz-natives test happy.
7534 return args[0];
7535 }
7536
7537 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7538
7539 double value = number->value();
7540 int exponent = number->get_exponent();
7541 int sign = number->get_sign();
7542
danno@chromium.org160a7b02011-04-18 15:51:38 +00007543 if (exponent < -1) {
7544 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7545 if (sign) return isolate->heap()->minus_zero_value();
7546 return Smi::FromInt(0);
7547 }
7548
7549 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7550 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007551 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007552 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007553 return Smi::FromInt(static_cast<int>(value + 0.5));
7554 }
7555
7556 // If the magnitude is big enough, there's no place for fraction part. If we
7557 // try to add 0.5 to this number, 1.0 will be added instead.
7558 if (exponent >= 52) {
7559 return number;
7560 }
7561
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007562 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007563
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007564 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007565 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007566}
7567
7568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007569RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007570 NoHandleAllocation ha;
7571 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007572 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007573
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007574 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007575 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007576}
7577
7578
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007579RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007580 NoHandleAllocation ha;
7581 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007582 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007583
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007584 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007585 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007586}
7587
7588
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007589RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007590 NoHandleAllocation ha;
7591 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007592 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007593
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007594 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007595 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007596}
7597
7598
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007599static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007600 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7601 181, 212, 243, 273, 304, 334};
7602 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7603 182, 213, 244, 274, 305, 335};
7604
7605 year += month / 12;
7606 month %= 12;
7607 if (month < 0) {
7608 year--;
7609 month += 12;
7610 }
7611
7612 ASSERT(month >= 0);
7613 ASSERT(month < 12);
7614
7615 // year_delta is an arbitrary number such that:
7616 // a) year_delta = -1 (mod 400)
7617 // b) year + year_delta > 0 for years in the range defined by
7618 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7619 // Jan 1 1970. This is required so that we don't run into integer
7620 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007621 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007622 // operations.
7623 static const int year_delta = 399999;
7624 static const int base_day = 365 * (1970 + year_delta) +
7625 (1970 + year_delta) / 4 -
7626 (1970 + year_delta) / 100 +
7627 (1970 + year_delta) / 400;
7628
7629 int year1 = year + year_delta;
7630 int day_from_year = 365 * year1 +
7631 year1 / 4 -
7632 year1 / 100 +
7633 year1 / 400 -
7634 base_day;
7635
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007636 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7637 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007638 }
7639
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007640 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007641}
7642
7643
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007644RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007645 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007646 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007647
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007648 CONVERT_SMI_ARG_CHECKED(year, 0);
7649 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007650
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007651 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007652}
7653
7654
7655static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7656static const int kDaysIn4Years = 4 * 365 + 1;
7657static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7658static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7659static const int kDays1970to2000 = 30 * 365 + 7;
7660static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7661 kDays1970to2000;
7662static const int kYearsOffset = 400000;
7663
7664static const char kDayInYear[] = {
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, 31,
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,
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 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7680 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7681 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7682 22, 23, 24, 25, 26, 27, 28, 29, 30,
7683 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7684 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7685 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7686 22, 23, 24, 25, 26, 27, 28, 29, 30,
7687 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7688 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7689
7690 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7691 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7692 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7693 22, 23, 24, 25, 26, 27, 28,
7694 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7695 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7696 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7697 22, 23, 24, 25, 26, 27, 28, 29, 30,
7698 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7699 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7700 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7701 22, 23, 24, 25, 26, 27, 28, 29, 30,
7702 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7703 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7704 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7705 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7706 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7707 22, 23, 24, 25, 26, 27, 28, 29, 30,
7708 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7709 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7710 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7711 22, 23, 24, 25, 26, 27, 28, 29, 30,
7712 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7713 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7714
7715 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7716 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7717 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7718 22, 23, 24, 25, 26, 27, 28, 29,
7719 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7720 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7721 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7722 22, 23, 24, 25, 26, 27, 28, 29, 30,
7723 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7724 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7725 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7726 22, 23, 24, 25, 26, 27, 28, 29, 30,
7727 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7728 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7729 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7730 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7731 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7732 22, 23, 24, 25, 26, 27, 28, 29, 30,
7733 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7734 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7735 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7736 22, 23, 24, 25, 26, 27, 28, 29, 30,
7737 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7738 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7739
7740 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7741 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7742 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7743 22, 23, 24, 25, 26, 27, 28,
7744 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7745 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7746 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7747 22, 23, 24, 25, 26, 27, 28, 29, 30,
7748 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7749 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7750 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7751 22, 23, 24, 25, 26, 27, 28, 29, 30,
7752 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7753 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7754 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7755 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7756 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7757 22, 23, 24, 25, 26, 27, 28, 29, 30,
7758 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7759 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7760 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7761 22, 23, 24, 25, 26, 27, 28, 29, 30,
7762 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7763 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7764
7765static const char kMonthInYear[] = {
7766 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,
7767 0, 0, 0, 0, 0, 0,
7768 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,
7769 1, 1, 1,
7770 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,
7771 2, 2, 2, 2, 2, 2,
7772 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,
7773 3, 3, 3, 3, 3,
7774 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,
7775 4, 4, 4, 4, 4, 4,
7776 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,
7777 5, 5, 5, 5, 5,
7778 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,
7779 6, 6, 6, 6, 6, 6,
7780 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,
7781 7, 7, 7, 7, 7, 7,
7782 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,
7783 8, 8, 8, 8, 8,
7784 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,
7785 9, 9, 9, 9, 9, 9,
7786 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7787 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7788 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7789 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7790
7791 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,
7792 0, 0, 0, 0, 0, 0,
7793 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,
7794 1, 1, 1,
7795 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,
7796 2, 2, 2, 2, 2, 2,
7797 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,
7798 3, 3, 3, 3, 3,
7799 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,
7800 4, 4, 4, 4, 4, 4,
7801 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,
7802 5, 5, 5, 5, 5,
7803 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,
7804 6, 6, 6, 6, 6, 6,
7805 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,
7806 7, 7, 7, 7, 7, 7,
7807 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,
7808 8, 8, 8, 8, 8,
7809 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,
7810 9, 9, 9, 9, 9, 9,
7811 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7812 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7813 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7814 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7815
7816 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,
7817 0, 0, 0, 0, 0, 0,
7818 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,
7819 1, 1, 1, 1,
7820 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,
7821 2, 2, 2, 2, 2, 2,
7822 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,
7823 3, 3, 3, 3, 3,
7824 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,
7825 4, 4, 4, 4, 4, 4,
7826 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,
7827 5, 5, 5, 5, 5,
7828 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,
7829 6, 6, 6, 6, 6, 6,
7830 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,
7831 7, 7, 7, 7, 7, 7,
7832 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,
7833 8, 8, 8, 8, 8,
7834 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,
7835 9, 9, 9, 9, 9, 9,
7836 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7837 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7838 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7839 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7840
7841 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,
7842 0, 0, 0, 0, 0, 0,
7843 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,
7844 1, 1, 1,
7845 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,
7846 2, 2, 2, 2, 2, 2,
7847 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,
7848 3, 3, 3, 3, 3,
7849 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,
7850 4, 4, 4, 4, 4, 4,
7851 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,
7852 5, 5, 5, 5, 5,
7853 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,
7854 6, 6, 6, 6, 6, 6,
7855 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,
7856 7, 7, 7, 7, 7, 7,
7857 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,
7858 8, 8, 8, 8, 8,
7859 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,
7860 9, 9, 9, 9, 9, 9,
7861 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7862 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7863 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7864 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7865
7866
7867// This function works for dates from 1970 to 2099.
7868static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007869 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007870#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007871 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007872#endif
7873
7874 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7875 date %= kDaysIn4Years;
7876
7877 month = kMonthInYear[date];
7878 day = kDayInYear[date];
7879
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007880 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007881}
7882
7883
7884static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007885 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007886#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007887 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007888#endif
7889
7890 date += kDaysOffset;
7891 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7892 date %= kDaysIn400Years;
7893
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007894 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007895
7896 date--;
7897 int yd1 = date / kDaysIn100Years;
7898 date %= kDaysIn100Years;
7899 year += 100 * yd1;
7900
7901 date++;
7902 int yd2 = date / kDaysIn4Years;
7903 date %= kDaysIn4Years;
7904 year += 4 * yd2;
7905
7906 date--;
7907 int yd3 = date / 365;
7908 date %= 365;
7909 year += yd3;
7910
7911 bool is_leap = (!yd1 || yd2) && !yd3;
7912
7913 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007914 ASSERT(is_leap || (date >= 0));
7915 ASSERT((date < 365) || (is_leap && (date < 366)));
7916 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007917 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7918 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007919
7920 if (is_leap) {
7921 day = kDayInYear[2*365 + 1 + date];
7922 month = kMonthInYear[2*365 + 1 + date];
7923 } else {
7924 day = kDayInYear[date];
7925 month = kMonthInYear[date];
7926 }
7927
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007928 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007929}
7930
7931
7932static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007933 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007934 if (date >= 0 && date < 32 * kDaysIn4Years) {
7935 DateYMDFromTimeAfter1970(date, year, month, day);
7936 } else {
7937 DateYMDFromTimeSlow(date, year, month, day);
7938 }
7939}
7940
7941
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007942RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007943 NoHandleAllocation ha;
7944 ASSERT(args.length() == 2);
7945
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007946 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007947 CONVERT_CHECKED(JSArray, res_array, args[1]);
7948
7949 int year, month, day;
7950 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7951
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007952 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7953 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007954 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007955
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007956 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7957 if (maybe->IsFailure()) return maybe;
7958 FixedArray* elms = FixedArray::cast(res_array->elements());
7959 elms->set(0, Smi::FromInt(year));
7960 elms->set(1, Smi::FromInt(month));
7961 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007962
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007963 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007964}
7965
7966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007967RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007968 HandleScope scope(isolate);
7969 ASSERT(args.length() == 3);
7970
7971 Handle<JSFunction> callee = args.at<JSFunction>(0);
7972 Object** parameters = reinterpret_cast<Object**>(args[1]);
7973 const int argument_count = Smi::cast(args[2])->value();
7974
7975 Handle<JSObject> result =
7976 isolate->factory()->NewArgumentsObject(callee, argument_count);
7977 // Allocate the elements if needed.
7978 int parameter_count = callee->shared()->formal_parameter_count();
7979 if (argument_count > 0) {
7980 if (parameter_count > 0) {
7981 int mapped_count = Min(argument_count, parameter_count);
7982 Handle<FixedArray> parameter_map =
7983 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7984 parameter_map->set_map(
7985 isolate->heap()->non_strict_arguments_elements_map());
7986
7987 Handle<Map> old_map(result->map());
7988 Handle<Map> new_map =
7989 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007990 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007991
7992 result->set_map(*new_map);
7993 result->set_elements(*parameter_map);
7994
7995 // Store the context and the arguments array at the beginning of the
7996 // parameter map.
7997 Handle<Context> context(isolate->context());
7998 Handle<FixedArray> arguments =
7999 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8000 parameter_map->set(0, *context);
8001 parameter_map->set(1, *arguments);
8002
8003 // Loop over the actual parameters backwards.
8004 int index = argument_count - 1;
8005 while (index >= mapped_count) {
8006 // These go directly in the arguments array and have no
8007 // corresponding slot in the parameter map.
8008 arguments->set(index, *(parameters - index - 1));
8009 --index;
8010 }
8011
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008012 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00008013 while (index >= 0) {
8014 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008015 Handle<String> name(scope_info->ParameterName(index));
8016 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00008017 bool duplicate = false;
8018 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008019 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008020 duplicate = true;
8021 break;
8022 }
8023 }
8024
8025 if (duplicate) {
8026 // This goes directly in the arguments array with a hole in the
8027 // parameter map.
8028 arguments->set(index, *(parameters - index - 1));
8029 parameter_map->set_the_hole(index + 2);
8030 } else {
8031 // The context index goes in the parameter map with a hole in the
8032 // arguments array.
8033 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008034 for (int j = 0; j < context_local_count; ++j) {
8035 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008036 context_index = j;
8037 break;
8038 }
8039 }
8040 ASSERT(context_index >= 0);
8041 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008042 parameter_map->set(index + 2, Smi::FromInt(
8043 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00008044 }
8045
8046 --index;
8047 }
8048 } else {
8049 // If there is no aliasing, the arguments object elements are not
8050 // special in any way.
8051 Handle<FixedArray> elements =
8052 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8053 result->set_elements(*elements);
8054 for (int i = 0; i < argument_count; ++i) {
8055 elements->set(i, *(parameters - i - 1));
8056 }
8057 }
8058 }
8059 return *result;
8060}
8061
8062
8063RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008064 NoHandleAllocation ha;
8065 ASSERT(args.length() == 3);
8066
8067 JSFunction* callee = JSFunction::cast(args[0]);
8068 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008069 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008070
lrn@chromium.org303ada72010-10-27 09:33:13 +00008071 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008072 { MaybeObject* maybe_result =
8073 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008074 if (!maybe_result->ToObject(&result)) return maybe_result;
8075 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008076 // Allocate the elements if needed.
8077 if (length > 0) {
8078 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008079 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008080 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008081 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8082 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008083
8084 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008085 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008086 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008087 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008088
8089 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008090 for (int i = 0; i < length; i++) {
8091 array->set(i, *--parameters, mode);
8092 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008093 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008094 }
8095 return result;
8096}
8097
8098
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008099RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008100 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008101 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00008102 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008103 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008104 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008105
whesse@chromium.org7b260152011-06-20 15:33:18 +00008106 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008107 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008108 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008109 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008110 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8111 context,
8112 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008113 return *result;
8114}
8115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008116
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008117// Find the arguments of the JavaScript function invocation that called
8118// into C++ code. Collect these in a newly allocated array of handles (possibly
8119// prefixed by a number of empty handles).
8120static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8121 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008122 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008123 // Find frame containing arguments passed to the caller.
8124 JavaScriptFrameIterator it;
8125 JavaScriptFrame* frame = it.frame();
8126 List<JSFunction*> functions(2);
8127 frame->GetFunctions(&functions);
8128 if (functions.length() > 1) {
8129 int inlined_frame_index = functions.length() - 1;
8130 JSFunction* inlined_function = functions[inlined_frame_index];
8131 int args_count = inlined_function->shared()->formal_parameter_count();
8132 ScopedVector<SlotRef> args_slots(args_count);
8133 SlotRef::ComputeSlotMappingForArguments(frame,
8134 inlined_frame_index,
8135 &args_slots);
8136
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008137 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008138 SmartArrayPointer<Handle<Object> > param_data(
8139 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008140 for (int i = 0; i < args_count; i++) {
8141 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008142 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008143 }
8144 return param_data;
8145 } else {
8146 it.AdvanceToArgumentsFrame();
8147 frame = it.frame();
8148 int args_count = frame->ComputeParametersCount();
8149
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008150 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008151 SmartArrayPointer<Handle<Object> > param_data(
8152 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008153 for (int i = 0; i < args_count; i++) {
8154 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008155 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008156 }
8157 return param_data;
8158 }
8159}
8160
8161
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008162RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8163 HandleScope scope(isolate);
8164 ASSERT(args.length() == 4);
8165 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
8166 RUNTIME_ASSERT(args[3]->IsNumber());
8167 Handle<Object> bindee = args.at<Object>(1);
8168
8169 // TODO(lrn): Create bound function in C++ code from premade shared info.
8170 bound_function->shared()->set_bound(true);
8171 // Get all arguments of calling function (Function.prototype.bind).
8172 int argc = 0;
8173 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8174 // Don't count the this-arg.
8175 if (argc > 0) {
8176 ASSERT(*arguments[0] == args[2]);
8177 argc--;
8178 } else {
8179 ASSERT(args[2]->IsUndefined());
8180 }
8181 // Initialize array of bindings (function, this, and any existing arguments
8182 // if the function was already bound).
8183 Handle<FixedArray> new_bindings;
8184 int i;
8185 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8186 Handle<FixedArray> old_bindings(
8187 JSFunction::cast(*bindee)->function_bindings());
8188 new_bindings =
8189 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8190 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8191 i = 0;
8192 for (int n = old_bindings->length(); i < n; i++) {
8193 new_bindings->set(i, old_bindings->get(i));
8194 }
8195 } else {
8196 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8197 new_bindings = isolate->factory()->NewFixedArray(array_size);
8198 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8199 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8200 i = 2;
8201 }
8202 // Copy arguments, skipping the first which is "this_arg".
8203 for (int j = 0; j < argc; j++, i++) {
8204 new_bindings->set(i, *arguments[j + 1]);
8205 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008206 new_bindings->set_map_no_write_barrier(
8207 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008208 bound_function->set_function_bindings(*new_bindings);
8209
8210 // Update length.
8211 Handle<String> length_symbol = isolate->factory()->length_symbol();
8212 Handle<Object> new_length(args.at<Object>(3));
8213 PropertyAttributes attr =
8214 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8215 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8216 return *bound_function;
8217}
8218
8219
8220RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8221 HandleScope handles(isolate);
8222 ASSERT(args.length() == 1);
danno@chromium.org2c456792011-11-11 12:00:53 +00008223 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008224 if (callable->IsJSFunction()) {
8225 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8226 if (function->shared()->bound()) {
8227 Handle<FixedArray> bindings(function->function_bindings());
8228 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8229 return *isolate->factory()->NewJSArrayWithElements(bindings);
8230 }
8231 }
8232 return isolate->heap()->undefined_value();
8233}
8234
8235
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008236RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008237 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008238 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008239 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008240 CONVERT_ARG_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008241 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008242
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008243 // The argument is a bound function. Extract its bound arguments
8244 // and callable.
8245 Handle<FixedArray> bound_args =
8246 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8247 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8248 Handle<Object> bound_function(
8249 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8250 ASSERT(!bound_function->IsJSFunction() ||
8251 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008252
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008253 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008254 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008255 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008256 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008257 param_data[i] = Handle<Object>(bound_args->get(
8258 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008259 }
8260
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008261 if (!bound_function->IsJSFunction()) {
8262 bool exception_thrown;
8263 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8264 &exception_thrown);
8265 if (exception_thrown) return Failure::Exception();
8266 }
8267 ASSERT(bound_function->IsJSFunction());
8268
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008269 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008270 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008271 Execution::New(Handle<JSFunction>::cast(bound_function),
8272 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008273 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008274 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008275 }
8276 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008277 return *result;
8278}
8279
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008280
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008281static void TrySettingInlineConstructStub(Isolate* isolate,
8282 Handle<JSFunction> function) {
8283 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008284 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008285 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008286 }
8287 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008288 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008289 Handle<Code> code = compiler.CompileConstructStub(function);
8290 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008291 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008292}
8293
8294
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008295RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008296 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008297 ASSERT(args.length() == 1);
8298
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008299 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008300
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008301 // If the constructor isn't a proper function we throw a type error.
8302 if (!constructor->IsJSFunction()) {
8303 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8304 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008305 isolate->factory()->NewTypeError("not_constructor", arguments);
8306 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008307 }
8308
8309 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008310
8311 // If function should not have prototype, construction is not allowed. In this
8312 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008313 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008314 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8315 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008316 isolate->factory()->NewTypeError("not_constructor", arguments);
8317 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008318 }
8319
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008320#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008321 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008322 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008323 if (debug->StepInActive()) {
8324 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008325 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008326#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008327
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008328 if (function->has_initial_map()) {
8329 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008330 // The 'Function' function ignores the receiver object when
8331 // called using 'new' and creates a new JSFunction object that
8332 // is returned. The receiver object is only used for error
8333 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008334 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008335 // allocate JSFunctions since it does not properly initialize
8336 // the shared part of the function. Since the receiver is
8337 // ignored anyway, we use the global object as the receiver
8338 // instead of a new JSFunction object. This way, errors are
8339 // reported the same way whether or not 'Function' is called
8340 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008341 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008342 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008343 }
8344
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008345 // The function should be compiled for the optimization hints to be
8346 // available. We cannot use EnsureCompiled because that forces a
8347 // compilation through the shared function info which makes it
8348 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008349 if (!function->is_compiled()) {
8350 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8351 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008352
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008353 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008354 if (!function->has_initial_map() &&
8355 shared->IsInobjectSlackTrackingInProgress()) {
8356 // The tracking is already in progress for another function. We can only
8357 // track one initial_map at a time, so we force the completion before the
8358 // function is called as a constructor for the first time.
8359 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008360 }
8361
8362 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008363 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8364 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008365 // Delay setting the stub if inobject slack tracking is in progress.
8366 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008367 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008368 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008369
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008370 isolate->counters()->constructed_objects()->Increment();
8371 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008372
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008373 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008374}
8375
8376
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008377RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008378 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008379 ASSERT(args.length() == 1);
8380
8381 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8382 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008383 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008384
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008385 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008386}
8387
8388
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008389RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008390 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008391 ASSERT(args.length() == 1);
8392
8393 Handle<JSFunction> function = args.at<JSFunction>(0);
8394#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008395 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008396 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008397 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008398 PrintF("]\n");
8399 }
8400#endif
8401
lrn@chromium.org34e60782011-09-15 07:25:40 +00008402 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008403 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008404 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008405 return Failure::Exception();
8406 }
8407
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008408 // All done. Return the compiled code.
8409 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008410 return function->code();
8411}
8412
8413
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008414RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008415 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008416 ASSERT(args.length() == 1);
8417 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008418
8419 // If the function is not compiled ignore the lazy
8420 // recompilation. This can happen if the debugger is activated and
8421 // the function is returned to the not compiled state.
8422 if (!function->shared()->is_compiled()) {
8423 function->ReplaceCode(function->shared()->code());
8424 return function->code();
8425 }
8426
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008427 // If the function is not optimizable or debugger is active continue using the
8428 // code from the full compiler.
8429 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008430 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008431 if (FLAG_trace_opt) {
8432 PrintF("[failed to optimize ");
8433 function->PrintName();
8434 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8435 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008436 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008437 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008438 function->ReplaceCode(function->shared()->code());
8439 return function->code();
8440 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008441 if (JSFunction::CompileOptimized(function,
8442 AstNode::kNoNumber,
8443 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008444 return function->code();
8445 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008446 if (FLAG_trace_opt) {
8447 PrintF("[failed to optimize ");
8448 function->PrintName();
8449 PrintF(": optimized compilation failed]\n");
8450 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008451 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008452 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008453}
8454
8455
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008456class ActivationsFinder : public ThreadVisitor {
8457 public:
8458 explicit ActivationsFinder(JSFunction* function)
8459 : function_(function), has_activations_(false) {}
8460
8461 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8462 if (has_activations_) return;
8463
8464 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8465 JavaScriptFrame* frame = it.frame();
8466 if (frame->is_optimized() && frame->function() == function_) {
8467 has_activations_ = true;
8468 return;
8469 }
8470 }
8471 }
8472
8473 bool has_activations() { return has_activations_; }
8474
8475 private:
8476 JSFunction* function_;
8477 bool has_activations_;
8478};
8479
8480
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008481RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008482 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008483 ASSERT(args.length() == 1);
8484 RUNTIME_ASSERT(args[0]->IsSmi());
8485 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008486 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008487 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8488 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008489 int frames = deoptimizer->output_count();
8490
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008491 deoptimizer->MaterializeHeapNumbers();
8492 delete deoptimizer;
8493
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008494 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008495 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008496 for (int i = 0; i < frames - 1; i++) it.Advance();
8497 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008498
8499 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008500 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008501 Handle<Object> arguments;
8502 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008503 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008504 if (arguments.is_null()) {
8505 // FunctionGetArguments can't throw an exception, so cast away the
8506 // doubt with an assert.
8507 arguments = Handle<Object>(
8508 Accessors::FunctionGetArguments(*function,
8509 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008510 ASSERT(*arguments != isolate->heap()->null_value());
8511 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008512 }
8513 frame->SetExpression(i, *arguments);
8514 }
8515 }
8516
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008517 if (type == Deoptimizer::EAGER) {
8518 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008519 }
8520
8521 // Avoid doing too much work when running with --always-opt and keep
8522 // the optimized code around.
8523 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008524 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008525 }
8526
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008527 // Find other optimized activations of the function.
8528 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008529 while (!it.done()) {
8530 JavaScriptFrame* frame = it.frame();
8531 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008532 has_other_activations = true;
8533 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008534 }
8535 it.Advance();
8536 }
8537
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008538 if (!has_other_activations) {
8539 ActivationsFinder activations_finder(*function);
8540 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8541 has_other_activations = activations_finder.has_activations();
8542 }
8543
8544 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008545 if (FLAG_trace_deopt) {
8546 PrintF("[removing optimized code for: ");
8547 function->PrintName();
8548 PrintF("]\n");
8549 }
8550 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008551 } else {
8552 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008553 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008554 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008555}
8556
8557
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008558RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008559 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008560 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008561 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008562}
8563
8564
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008565RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008566 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008567 ASSERT(args.length() == 1);
8568 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008569 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008570
8571 Deoptimizer::DeoptimizeFunction(*function);
8572
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008573 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008574}
8575
8576
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008577RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8578#if defined(USE_SIMULATOR)
8579 return isolate->heap()->true_value();
8580#else
8581 return isolate->heap()->false_value();
8582#endif
8583}
8584
8585
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008586RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8587 HandleScope scope(isolate);
8588 ASSERT(args.length() == 1);
8589 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8590 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8591 function->MarkForLazyRecompilation();
8592 return isolate->heap()->undefined_value();
8593}
8594
8595
lrn@chromium.org1c092762011-05-09 09:42:16 +00008596RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8597 HandleScope scope(isolate);
8598 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008599 // The least significant bit (after untagging) indicates whether the
8600 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008601 if (!V8::UseCrankshaft()) {
8602 return Smi::FromInt(4); // 4 == "never".
8603 }
8604 if (FLAG_always_opt) {
8605 return Smi::FromInt(3); // 3 == "always".
8606 }
8607 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8608 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8609 : Smi::FromInt(2); // 2 == "no".
8610}
8611
8612
8613RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8614 HandleScope scope(isolate);
8615 ASSERT(args.length() == 1);
8616 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8617 return Smi::FromInt(function->shared()->opt_count());
8618}
8619
8620
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008621RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008622 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008623 ASSERT(args.length() == 1);
8624 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8625
8626 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008627 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008628
8629 // We have hit a back edge in an unoptimized frame for a function that was
8630 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008631 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008632 // Keep track of whether we've succeeded in optimizing.
8633 bool succeeded = unoptimized->optimizable();
8634 if (succeeded) {
8635 // If we are trying to do OSR when there are already optimized
8636 // activations of the function, it means (a) the function is directly or
8637 // indirectly recursive and (b) an optimized invocation has been
8638 // deoptimized so that we are currently in an unoptimized activation.
8639 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008640 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008641 while (succeeded && !it.done()) {
8642 JavaScriptFrame* frame = it.frame();
8643 succeeded = !frame->is_optimized() || frame->function() != *function;
8644 it.Advance();
8645 }
8646 }
8647
8648 int ast_id = AstNode::kNoNumber;
8649 if (succeeded) {
8650 // The top JS function is this one, the PC is somewhere in the
8651 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008652 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008653 JavaScriptFrame* frame = it.frame();
8654 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008655 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008656 ASSERT(unoptimized->contains(frame->pc()));
8657
8658 // Use linear search of the unoptimized code's stack check table to find
8659 // the AST id matching the PC.
8660 Address start = unoptimized->instruction_start();
8661 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008662 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008663 uint32_t table_length = Memory::uint32_at(table_cursor);
8664 table_cursor += kIntSize;
8665 for (unsigned i = 0; i < table_length; ++i) {
8666 // Table entries are (AST id, pc offset) pairs.
8667 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8668 if (pc_offset == target_pc_offset) {
8669 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8670 break;
8671 }
8672 table_cursor += 2 * kIntSize;
8673 }
8674 ASSERT(ast_id != AstNode::kNoNumber);
8675 if (FLAG_trace_osr) {
8676 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8677 function->PrintName();
8678 PrintF("]\n");
8679 }
8680
8681 // Try to compile the optimized code. A true return value from
8682 // CompileOptimized means that compilation succeeded, not necessarily
8683 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008684 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008685 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008686 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8687 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008688 if (data->OsrPcOffset()->value() >= 0) {
8689 if (FLAG_trace_osr) {
8690 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008691 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008692 }
8693 ASSERT(data->OsrAstId()->value() == ast_id);
8694 } else {
8695 // We may never generate the desired OSR entry if we emit an
8696 // early deoptimize.
8697 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008698 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008699 } else {
8700 succeeded = false;
8701 }
8702 }
8703
8704 // Revert to the original stack checks in the original unoptimized code.
8705 if (FLAG_trace_osr) {
8706 PrintF("[restoring original stack checks in ");
8707 function->PrintName();
8708 PrintF("]\n");
8709 }
8710 StackCheckStub check_stub;
8711 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008712 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008713 Deoptimizer::RevertStackCheckCode(*unoptimized,
8714 *check_code,
8715 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008716
8717 // Allow OSR only at nesting level zero again.
8718 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8719
8720 // If the optimization attempt succeeded, return the AST id tagged as a
8721 // smi. This tells the builtin that we need to translate the unoptimized
8722 // frame to an optimized one.
8723 if (succeeded) {
8724 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8725 return Smi::FromInt(ast_id);
8726 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008727 if (function->IsMarkedForLazyRecompilation()) {
8728 function->ReplaceCode(function->shared()->code());
8729 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008730 return Smi::FromInt(-1);
8731 }
8732}
8733
8734
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008735RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8736 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8737 return isolate->heap()->undefined_value();
8738}
8739
8740
danno@chromium.orgc612e022011-11-10 11:38:15 +00008741RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8742 HandleScope scope(isolate);
8743 ASSERT(args.length() >= 2);
8744 CONVERT_CHECKED(JSReceiver, fun, args[args.length() - 1]);
8745 Object* receiver = args[0];
8746 int argc = args.length() - 2;
8747
8748 // If there are too many arguments, allocate argv via malloc.
8749 const int argv_small_size = 10;
8750 Handle<Object> argv_small_buffer[argv_small_size];
8751 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8752 Handle<Object>* argv = argv_small_buffer;
8753 if (argc > argv_small_size) {
8754 argv = new Handle<Object>[argc];
8755 if (argv == NULL) return isolate->StackOverflow();
8756 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8757 }
8758
8759 for (int i = 0; i < argc; ++i) {
8760 MaybeObject* maybe = args[1 + i];
8761 Object* object;
8762 if (!maybe->To<Object>(&object)) return maybe;
8763 argv[i] = Handle<Object>(object);
8764 }
8765
8766 bool threw;
8767 Handle<JSReceiver> hfun(fun);
8768 Handle<Object> hreceiver(receiver);
8769 Handle<Object> result =
8770 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8771
8772 if (threw) return Failure::Exception();
8773 return *result;
8774}
8775
8776
lrn@chromium.org34e60782011-09-15 07:25:40 +00008777RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8778 HandleScope scope(isolate);
8779 ASSERT(args.length() == 5);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008780 CONVERT_ARG_CHECKED(JSReceiver, fun, 0);
8781 Handle<Object> receiver = args.at<Object>(1);
8782 CONVERT_ARG_CHECKED(JSObject, arguments, 2);
8783 CONVERT_SMI_ARG_CHECKED(offset, 3);
8784 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008785 ASSERT(offset >= 0);
8786 ASSERT(argc >= 0);
8787
8788 // If there are too many arguments, allocate argv via malloc.
8789 const int argv_small_size = 10;
8790 Handle<Object> argv_small_buffer[argv_small_size];
8791 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8792 Handle<Object>* argv = argv_small_buffer;
8793 if (argc > argv_small_size) {
8794 argv = new Handle<Object>[argc];
8795 if (argv == NULL) return isolate->StackOverflow();
8796 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8797 }
8798
8799 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008800 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008801 }
8802
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008803 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008804 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008805 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008806
8807 if (threw) return Failure::Exception();
8808 return *result;
8809}
8810
8811
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008812RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008813 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008814 ASSERT(args.length() == 1);
8815 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8816 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8817}
8818
8819
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008820RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008821 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008822 ASSERT(args.length() == 1);
8823 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8824 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8825}
8826
8827
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008828RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008829 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008830 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008831
kasper.lund7276f142008-07-30 08:49:36 +00008832 CONVERT_CHECKED(JSFunction, function, args[0]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008833 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008834 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008835 { MaybeObject* maybe_result =
8836 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008837 if (!maybe_result->ToObject(&result)) return maybe_result;
8838 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008839
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008840 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008841
kasper.lund7276f142008-07-30 08:49:36 +00008842 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008843}
8844
lrn@chromium.org303ada72010-10-27 09:33:13 +00008845
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008846RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8847 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008848 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008849 JSObject* extension_object;
8850 if (args[0]->IsJSObject()) {
8851 extension_object = JSObject::cast(args[0]);
8852 } else {
8853 // Convert the object to a proper JavaScript object.
8854 MaybeObject* maybe_js_object = args[0]->ToObject();
8855 if (!maybe_js_object->To(&extension_object)) {
8856 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8857 HandleScope scope(isolate);
8858 Handle<Object> handle = args.at<Object>(0);
8859 Handle<Object> result =
8860 isolate->factory()->NewTypeError("with_expression",
8861 HandleVector(&handle, 1));
8862 return isolate->Throw(*result);
8863 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008864 return maybe_js_object;
8865 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008866 }
8867 }
8868
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008869 JSFunction* function;
8870 if (args[1]->IsSmi()) {
8871 // A smi sentinel indicates a context nested inside global code rather
8872 // than some function. There is a canonical empty function that can be
8873 // gotten from the global context.
8874 function = isolate->context()->global_context()->closure();
8875 } else {
8876 function = JSFunction::cast(args[1]);
8877 }
8878
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008879 Context* context;
8880 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008881 isolate->heap()->AllocateWithContext(function,
8882 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008883 extension_object);
8884 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008885 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008886 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008887}
8888
8889
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008890RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008891 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008892 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008893 String* name = String::cast(args[0]);
8894 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008895 JSFunction* function;
8896 if (args[2]->IsSmi()) {
8897 // A smi sentinel indicates a context nested inside global code rather
8898 // than some function. There is a canonical empty function that can be
8899 // gotten from the global context.
8900 function = isolate->context()->global_context()->closure();
8901 } else {
8902 function = JSFunction::cast(args[2]);
8903 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008904 Context* context;
8905 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008906 isolate->heap()->AllocateCatchContext(function,
8907 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008908 name,
8909 thrown_object);
8910 if (!maybe_context->To(&context)) return maybe_context;
8911 isolate->set_context(context);
8912 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008913}
8914
8915
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008916RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8917 NoHandleAllocation ha;
8918 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008919 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008920 JSFunction* function;
8921 if (args[1]->IsSmi()) {
8922 // A smi sentinel indicates a context nested inside global code rather
8923 // than some function. There is a canonical empty function that can be
8924 // gotten from the global context.
8925 function = isolate->context()->global_context()->closure();
8926 } else {
8927 function = JSFunction::cast(args[1]);
8928 }
8929 Context* context;
8930 MaybeObject* maybe_context =
8931 isolate->heap()->AllocateBlockContext(function,
8932 isolate->context(),
8933 scope_info);
8934 if (!maybe_context->To(&context)) return maybe_context;
8935 isolate->set_context(context);
8936 return context;
8937}
8938
8939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008940RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008941 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008942 ASSERT(args.length() == 2);
8943
8944 CONVERT_ARG_CHECKED(Context, context, 0);
8945 CONVERT_ARG_CHECKED(String, name, 1);
8946
8947 int index;
8948 PropertyAttributes attributes;
8949 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008950 BindingFlags binding_flags;
8951 Handle<Object> holder = context->Lookup(name,
8952 flags,
8953 &index,
8954 &attributes,
8955 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008956
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008957 // If the slot was not found the result is true.
8958 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008959 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008960 }
8961
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008962 // If the slot was found in a context, it should be DONT_DELETE.
8963 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008964 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008965 }
8966
8967 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008968 // the global object, or the subject of a with. Try to delete it
8969 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008970 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008971 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008972}
8973
8974
ager@chromium.orga1645e22009-09-09 19:27:10 +00008975// A mechanism to return a pair of Object pointers in registers (if possible).
8976// How this is achieved is calling convention-dependent.
8977// All currently supported x86 compiles uses calling conventions that are cdecl
8978// variants where a 64-bit value is returned in two 32-bit registers
8979// (edx:eax on ia32, r1:r0 on ARM).
8980// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8981// In Win64 calling convention, a struct of two pointers is returned in memory,
8982// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008983#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008984struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008985 MaybeObject* x;
8986 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008987};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008988
lrn@chromium.org303ada72010-10-27 09:33:13 +00008989static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008990 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008991 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8992 // In Win64 they are assigned to a hidden first argument.
8993 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008994}
8995#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008996typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008997static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008998 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008999 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009000}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009001#endif
9002
9003
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009004static inline MaybeObject* Unhole(Heap* heap,
9005 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009006 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009007 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
9008 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009009 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009010}
9011
9012
danno@chromium.org40cb8782011-05-25 07:58:50 +00009013static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
9014 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009015 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009016 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009017 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009018 JSFunction* context_extension_function =
9019 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009020 // If the holder isn't a context extension object, we just return it
9021 // as the receiver. This allows arguments objects to be used as
9022 // receivers, but only if they are put in the context scope chain
9023 // explicitly via a with-statement.
9024 Object* constructor = holder->map()->constructor();
9025 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00009026 // Fall back to using the global object as the implicit receiver if
9027 // the property turns out to be a local variable allocated in a
9028 // context extension object - introduced via eval. Implicit global
9029 // receivers are indicated with the hole value.
9030 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009031}
9032
9033
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009034static ObjectPair LoadContextSlotHelper(Arguments args,
9035 Isolate* isolate,
9036 bool throw_error) {
9037 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00009038 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009039
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009040 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009041 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009042 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009043 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009044 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009045
9046 int index;
9047 PropertyAttributes attributes;
9048 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009049 BindingFlags binding_flags;
9050 Handle<Object> holder = context->Lookup(name,
9051 flags,
9052 &index,
9053 &attributes,
9054 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009055
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009056 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009057 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009058 ASSERT(holder->IsContext());
9059 // If the "property" we were looking for is a local variable, the
9060 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00009061 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009062 // Use the hole as the receiver to signal that the receiver is implicit
9063 // and that the global receiver should be used (as distinguished from an
9064 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00009065 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009066 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009067 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009068 switch (binding_flags) {
9069 case MUTABLE_CHECK_INITIALIZED:
9070 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9071 if (value->IsTheHole()) {
9072 Handle<Object> reference_error =
9073 isolate->factory()->NewReferenceError("not_defined",
9074 HandleVector(&name, 1));
9075 return MakePair(isolate->Throw(*reference_error), NULL);
9076 }
9077 // FALLTHROUGH
9078 case MUTABLE_IS_INITIALIZED:
9079 case IMMUTABLE_IS_INITIALIZED:
9080 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9081 ASSERT(!value->IsTheHole());
9082 return MakePair(value, *receiver);
9083 case IMMUTABLE_CHECK_INITIALIZED:
9084 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9085 case MISSING_BINDING:
9086 UNREACHABLE();
9087 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009088 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009089 }
9090
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009091 // Otherwise, if the slot was found the holder is a context extension
9092 // object, subject of a with, or a global object. We read the named
9093 // property from it.
9094 if (!holder.is_null()) {
9095 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9096 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009097 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009098 Handle<Object> receiver_handle(object->IsGlobalObject()
9099 ? GlobalObject::cast(*object)->global_receiver()
9100 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009101
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009102 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009103 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009104 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009105 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009106 }
9107
9108 if (throw_error) {
9109 // The property doesn't exist - throw exception.
9110 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009111 isolate->factory()->NewReferenceError("not_defined",
9112 HandleVector(&name, 1));
9113 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009114 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009115 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009116 return MakePair(isolate->heap()->undefined_value(),
9117 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009118 }
9119}
9120
9121
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009122RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009123 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009124}
9125
9126
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009127RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009128 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009129}
9130
9131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009132RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009133 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009134 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009135
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009136 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009137 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009138 CONVERT_ARG_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009139 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9140 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9141 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009142
9143 int index;
9144 PropertyAttributes attributes;
9145 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009146 BindingFlags binding_flags;
9147 Handle<Object> holder = context->Lookup(name,
9148 flags,
9149 &index,
9150 &attributes,
9151 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009152
9153 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009154 // The property was found in a context slot.
9155 Handle<Context> context = Handle<Context>::cast(holder);
9156 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9157 context->get(index)->IsTheHole()) {
9158 Handle<Object> error =
9159 isolate->factory()->NewReferenceError("not_defined",
9160 HandleVector(&name, 1));
9161 return isolate->Throw(*error);
9162 }
9163 // Ignore if read_only variable.
9164 if ((attributes & READ_ONLY) == 0) {
9165 // Context is a fixed array and set cannot fail.
9166 context->set(index, *value);
9167 } else if (strict_mode == kStrictMode) {
9168 // Setting read only property in strict mode.
9169 Handle<Object> error =
9170 isolate->factory()->NewTypeError("strict_cannot_assign",
9171 HandleVector(&name, 1));
9172 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009173 }
9174 return *value;
9175 }
9176
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009177 // Slow case: The property is not in a context slot. It is either in a
9178 // context extension object, a property of the subject of a with, or a
9179 // property of the global object.
9180 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009181
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009182 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009183 // The property exists on the holder.
9184 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009185 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009186 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009187 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009188
9189 if (strict_mode == kStrictMode) {
9190 // Throw in strict mode (assignment to undefined variable).
9191 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009192 isolate->factory()->NewReferenceError(
9193 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009194 return isolate->Throw(*error);
9195 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009196 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009197 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009198 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009199 }
9200
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009201 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009202 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009203 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009204 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009205 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009206 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009207 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009208 // Setting read only property in strict mode.
9209 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009210 isolate->factory()->NewTypeError(
9211 "strict_cannot_assign", HandleVector(&name, 1));
9212 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009213 }
9214 return *value;
9215}
9216
9217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009218RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009219 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009220 ASSERT(args.length() == 1);
9221
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009222 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009223}
9224
9225
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009226RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009227 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009228 ASSERT(args.length() == 1);
9229
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009230 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009231}
9232
9233
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009234RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009235 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009236 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009237}
9238
9239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009240RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009241 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009242 ASSERT(args.length() == 1);
9243
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009244 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009245 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009246 isolate->factory()->NewReferenceError("not_defined",
9247 HandleVector(&name, 1));
9248 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009249}
9250
9251
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009252RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009253 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009254
9255 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009256 if (isolate->stack_guard()->IsStackOverflow()) {
9257 NoHandleAllocation na;
9258 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009259 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009260
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009261 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009262}
9263
9264
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009265static int StackSize() {
9266 int n = 0;
9267 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9268 return n;
9269}
9270
9271
9272static void PrintTransition(Object* result) {
9273 // indentation
9274 { const int nmax = 80;
9275 int n = StackSize();
9276 if (n <= nmax)
9277 PrintF("%4d:%*s", n, n, "");
9278 else
9279 PrintF("%4d:%*s", n, nmax, "...");
9280 }
9281
9282 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009283 JavaScriptFrame::PrintTop(stdout, true, false);
9284 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009285 } else {
9286 // function result
9287 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009288 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009289 PrintF("\n");
9290 }
9291}
9292
9293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009294RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009295 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009296 NoHandleAllocation ha;
9297 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009298 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009299}
9300
9301
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009302RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009303 NoHandleAllocation ha;
9304 PrintTransition(args[0]);
9305 return args[0]; // return TOS
9306}
9307
9308
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009309RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009310 NoHandleAllocation ha;
9311 ASSERT(args.length() == 1);
9312
9313#ifdef DEBUG
9314 if (args[0]->IsString()) {
9315 // If we have a string, assume it's a code "marker"
9316 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009317 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009318 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009319 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9320 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009321 } else {
9322 PrintF("DebugPrint: ");
9323 }
9324 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009325 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009326 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009327 HeapObject::cast(args[0])->map()->Print();
9328 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009329#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009330 // ShortPrint is available in release mode. Print is not.
9331 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009332#endif
9333 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009334 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009335
9336 return args[0]; // return TOS
9337}
9338
9339
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009340RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009341 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009342 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009343 isolate->PrintStack();
9344 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009345}
9346
9347
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009348RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009349 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009350 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009351
9352 // According to ECMA-262, section 15.9.1, page 117, the precision of
9353 // the number in a Date object representing a particular instant in
9354 // time is milliseconds. Therefore, we floor the result of getting
9355 // the OS time.
9356 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009357 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009358}
9359
9360
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009361RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009362 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009363 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009364
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009365 CONVERT_ARG_CHECKED(String, str, 0);
9366 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009367
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009368 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009369
9370 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009371 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009372 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009373 RUNTIME_ASSERT(output->HasFastElements());
9374
9375 AssertNoAllocation no_allocation;
9376
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009377 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009378 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9379 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009380 String::FlatContent str_content = str->GetFlatContent();
9381 if (str_content.IsAscii()) {
9382 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009383 output_array,
9384 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009385 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009386 ASSERT(str_content.IsTwoByte());
9387 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009388 output_array,
9389 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009390 }
9391
9392 if (result) {
9393 return *output;
9394 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009395 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009396 }
9397}
9398
9399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009400RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009401 NoHandleAllocation ha;
9402 ASSERT(args.length() == 1);
9403
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009404 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009405 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009406 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009407}
9408
9409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009410RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009411 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009412 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009414 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009415}
9416
9417
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009418RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009419 NoHandleAllocation ha;
9420 ASSERT(args.length() == 1);
9421
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009422 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009423 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009424}
9425
9426
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009427RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009428 ASSERT(args.length() == 1);
9429 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009430 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009431 return JSGlobalObject::cast(global)->global_receiver();
9432}
9433
9434
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009435RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009436 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009437 ASSERT_EQ(1, args.length());
9438 CONVERT_ARG_CHECKED(String, source, 0);
9439
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009440 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009441 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009442 Handle<Object> result;
9443 if (source->IsSeqAsciiString()) {
9444 result = JsonParser<true>::Parse(source);
9445 } else {
9446 result = JsonParser<false>::Parse(source);
9447 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009448 if (result.is_null()) {
9449 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009450 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009451 return Failure::Exception();
9452 }
9453 return *result;
9454}
9455
9456
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009457bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9458 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009459 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9460 // Check with callback if set.
9461 AllowCodeGenerationFromStringsCallback callback =
9462 isolate->allow_code_gen_callback();
9463 if (callback == NULL) {
9464 // No callback set and code generation disallowed.
9465 return false;
9466 } else {
9467 // Callback set. Let it decide if code generation is allowed.
9468 VMState state(isolate, EXTERNAL);
9469 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009470 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009471}
9472
9473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009474RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009475 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009476 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009477 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009478
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009479 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009480 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009481
9482 // Check if global context allows code generation from
9483 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009484 if (context->allow_code_gen_from_strings()->IsFalse() &&
9485 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009486 return isolate->Throw(*isolate->factory()->NewError(
9487 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9488 }
9489
9490 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009491 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009492 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009493 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009494 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009495 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9496 context,
9497 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009498 return *fun;
9499}
9500
9501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009502static ObjectPair CompileGlobalEval(Isolate* isolate,
9503 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009504 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009505 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009506 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009507 Handle<Context> context = Handle<Context>(isolate->context());
9508 Handle<Context> global_context = Handle<Context>(context->global_context());
9509
9510 // Check if global context allows code generation from
9511 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009512 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9513 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009514 isolate->Throw(*isolate->factory()->NewError(
9515 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9516 return MakePair(Failure::Exception(), NULL);
9517 }
9518
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009519 // Deal with a normal eval call with a string argument. Compile it
9520 // and return the compiled function bound in the local context.
9521 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9522 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009523 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009524 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009525 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009526 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009527 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009528 Handle<JSFunction> compiled =
9529 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009530 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009531 return MakePair(*compiled, *receiver);
9532}
9533
9534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009535RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009536 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009537
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009538 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009539 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009540
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009541 // If "eval" didn't refer to the original GlobalEval, it's not a
9542 // direct call to eval.
9543 // (And even if it is, but the first argument isn't a string, just let
9544 // execution default to an indirect call to eval, which will also return
9545 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009546 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009547 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009548 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009549 }
9550
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009551 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009552 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009553 return CompileGlobalEval(isolate,
9554 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009555 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009556 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009557 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009558}
9559
9560
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009561RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009562 // This utility adjusts the property attributes for newly created Function
9563 // object ("new Function(...)") by changing the map.
9564 // All it does is changing the prototype property to enumerable
9565 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009566 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009567 ASSERT(args.length() == 1);
9568 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009569
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009570 Handle<Map> map = func->shared()->is_classic_mode()
9571 ? isolate->function_instance_map()
9572 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009573
9574 ASSERT(func->map()->instance_type() == map->instance_type());
9575 ASSERT(func->map()->instance_size() == map->instance_size());
9576 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009577 return *func;
9578}
9579
9580
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009581RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009582 // Allocate a block of memory in NewSpace (filled with a filler).
9583 // Use as fallback for allocation in generated code when NewSpace
9584 // is full.
9585 ASSERT(args.length() == 1);
9586 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9587 int size = size_smi->value();
9588 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9589 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009590 Heap* heap = isolate->heap();
9591 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009592 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009593 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009594 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009595 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009596 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009597 }
9598 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009599 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009600}
9601
9602
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009603// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009604// array. Returns true if the element was pushed on the stack and
9605// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009606RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009607 ASSERT(args.length() == 2);
9608 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009609 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009610 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009611 int length = Smi::cast(array->length())->value();
9612 FixedArray* elements = FixedArray::cast(array->elements());
9613 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009614 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009615 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009616 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009617 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009618 { MaybeObject* maybe_obj =
9619 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009620 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9621 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009622 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009623}
9624
9625
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009626/**
9627 * A simple visitor visits every element of Array's.
9628 * The backend storage can be a fixed array for fast elements case,
9629 * or a dictionary for sparse array. Since Dictionary is a subtype
9630 * of FixedArray, the class can be used by both fast and slow cases.
9631 * The second parameter of the constructor, fast_elements, specifies
9632 * whether the storage is a FixedArray or Dictionary.
9633 *
9634 * An index limit is used to deal with the situation that a result array
9635 * length overflows 32-bit non-negative integer.
9636 */
9637class ArrayConcatVisitor {
9638 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009639 ArrayConcatVisitor(Isolate* isolate,
9640 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009641 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009642 isolate_(isolate),
9643 storage_(Handle<FixedArray>::cast(
9644 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009645 index_offset_(0u),
9646 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009647
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009648 ~ArrayConcatVisitor() {
9649 clear_storage();
9650 }
9651
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009652 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009653 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009654 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009655
9656 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009657 if (index < static_cast<uint32_t>(storage_->length())) {
9658 storage_->set(index, *elm);
9659 return;
9660 }
9661 // Our initial estimate of length was foiled, possibly by
9662 // getters on the arrays increasing the length of later arrays
9663 // during iteration.
9664 // This shouldn't happen in anything but pathological cases.
9665 SetDictionaryMode(index);
9666 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009667 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009668 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009669 Handle<SeededNumberDictionary> dict(
9670 SeededNumberDictionary::cast(*storage_));
9671 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009672 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009673 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009674 // Dictionary needed to grow.
9675 clear_storage();
9676 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009677 }
9678}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009679
9680 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009681 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9682 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009683 } else {
9684 index_offset_ += delta;
9685 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009686 }
9687
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009688 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009689 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009690 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009691 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009692 Handle<Map> map;
9693 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009694 map = isolate_->factory()->GetElementsTransitionMap(array,
9695 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009696 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009697 map = isolate_->factory()->GetElementsTransitionMap(array,
9698 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009699 }
9700 array->set_map(*map);
9701 array->set_length(*length);
9702 array->set_elements(*storage_);
9703 return array;
9704 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009705
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009706 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009707 // Convert storage to dictionary mode.
9708 void SetDictionaryMode(uint32_t index) {
9709 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009710 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009711 Handle<SeededNumberDictionary> slow_storage(
9712 isolate_->factory()->NewSeededNumberDictionary(
9713 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009714 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9715 for (uint32_t i = 0; i < current_length; i++) {
9716 HandleScope loop_scope;
9717 Handle<Object> element(current_storage->get(i));
9718 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009719 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009720 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009721 if (!new_storage.is_identical_to(slow_storage)) {
9722 slow_storage = loop_scope.CloseAndEscape(new_storage);
9723 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009724 }
9725 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009726 clear_storage();
9727 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009728 fast_elements_ = false;
9729 }
9730
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009731 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009732 isolate_->global_handles()->Destroy(
9733 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009734 }
9735
9736 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009737 storage_ = Handle<FixedArray>::cast(
9738 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009739 }
9740
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009741 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009742 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009743 // Index after last seen index. Always less than or equal to
9744 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009745 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009746 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009747};
9748
9749
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009750static uint32_t EstimateElementCount(Handle<JSArray> array) {
9751 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9752 int element_count = 0;
9753 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009754 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009755 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009756 // Fast elements can't have lengths that are not representable by
9757 // a 32-bit signed integer.
9758 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9759 int fast_length = static_cast<int>(length);
9760 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9761 for (int i = 0; i < fast_length; i++) {
9762 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009763 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009764 break;
9765 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009766 case FAST_DOUBLE_ELEMENTS:
9767 // TODO(1810): Decide if it's worthwhile to implement this.
9768 UNREACHABLE();
9769 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009770 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009771 Handle<SeededNumberDictionary> dictionary(
9772 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009773 int capacity = dictionary->Capacity();
9774 for (int i = 0; i < capacity; i++) {
9775 Handle<Object> key(dictionary->KeyAt(i));
9776 if (dictionary->IsKey(*key)) {
9777 element_count++;
9778 }
9779 }
9780 break;
9781 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009782 case NON_STRICT_ARGUMENTS_ELEMENTS:
9783 case EXTERNAL_BYTE_ELEMENTS:
9784 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9785 case EXTERNAL_SHORT_ELEMENTS:
9786 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9787 case EXTERNAL_INT_ELEMENTS:
9788 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9789 case EXTERNAL_FLOAT_ELEMENTS:
9790 case EXTERNAL_DOUBLE_ELEMENTS:
9791 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009792 // External arrays are always dense.
9793 return length;
9794 }
9795 // As an estimate, we assume that the prototype doesn't contain any
9796 // inherited elements.
9797 return element_count;
9798}
9799
9800
9801
9802template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009803static void IterateExternalArrayElements(Isolate* isolate,
9804 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009805 bool elements_are_ints,
9806 bool elements_are_guaranteed_smis,
9807 ArrayConcatVisitor* visitor) {
9808 Handle<ExternalArrayClass> array(
9809 ExternalArrayClass::cast(receiver->elements()));
9810 uint32_t len = static_cast<uint32_t>(array->length());
9811
9812 ASSERT(visitor != NULL);
9813 if (elements_are_ints) {
9814 if (elements_are_guaranteed_smis) {
9815 for (uint32_t j = 0; j < len; j++) {
9816 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009817 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009818 visitor->visit(j, e);
9819 }
9820 } else {
9821 for (uint32_t j = 0; j < len; j++) {
9822 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009823 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009824 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9825 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9826 visitor->visit(j, e);
9827 } else {
9828 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009829 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009830 visitor->visit(j, e);
9831 }
9832 }
9833 }
9834 } else {
9835 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009836 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009837 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009838 visitor->visit(j, e);
9839 }
9840 }
9841}
9842
9843
9844// Used for sorting indices in a List<uint32_t>.
9845static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9846 uint32_t a = *ap;
9847 uint32_t b = *bp;
9848 return (a == b) ? 0 : (a < b) ? -1 : 1;
9849}
9850
9851
9852static void CollectElementIndices(Handle<JSObject> object,
9853 uint32_t range,
9854 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009855 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009856 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009857 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009858 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009859 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9860 uint32_t length = static_cast<uint32_t>(elements->length());
9861 if (range < length) length = range;
9862 for (uint32_t i = 0; i < length; i++) {
9863 if (!elements->get(i)->IsTheHole()) {
9864 indices->Add(i);
9865 }
9866 }
9867 break;
9868 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009869 case FAST_DOUBLE_ELEMENTS: {
9870 // TODO(1810): Decide if it's worthwhile to implement this.
9871 UNREACHABLE();
9872 break;
9873 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009874 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009875 Handle<SeededNumberDictionary> dict(
9876 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009877 uint32_t capacity = dict->Capacity();
9878 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009879 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009880 Handle<Object> k(dict->KeyAt(j));
9881 if (dict->IsKey(*k)) {
9882 ASSERT(k->IsNumber());
9883 uint32_t index = static_cast<uint32_t>(k->Number());
9884 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009885 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009886 }
9887 }
9888 }
9889 break;
9890 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009891 default: {
9892 int dense_elements_length;
9893 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009894 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009895 dense_elements_length =
9896 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009897 break;
9898 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009899 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009900 dense_elements_length =
9901 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009902 break;
9903 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009904 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009905 dense_elements_length =
9906 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009907 break;
9908 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009909 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009910 dense_elements_length =
9911 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009912 break;
9913 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009914 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009915 dense_elements_length =
9916 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009917 break;
9918 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009919 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009920 dense_elements_length =
9921 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009922 break;
9923 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009924 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009925 dense_elements_length =
9926 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009927 break;
9928 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009929 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009930 dense_elements_length =
9931 ExternalFloatArray::cast(object->elements())->length();
9932 break;
9933 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009934 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009935 dense_elements_length =
9936 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009937 break;
9938 }
9939 default:
9940 UNREACHABLE();
9941 dense_elements_length = 0;
9942 break;
9943 }
9944 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9945 if (range <= length) {
9946 length = range;
9947 // We will add all indices, so we might as well clear it first
9948 // and avoid duplicates.
9949 indices->Clear();
9950 }
9951 for (uint32_t i = 0; i < length; i++) {
9952 indices->Add(i);
9953 }
9954 if (length == range) return; // All indices accounted for already.
9955 break;
9956 }
9957 }
9958
9959 Handle<Object> prototype(object->GetPrototype());
9960 if (prototype->IsJSObject()) {
9961 // The prototype will usually have no inherited element indices,
9962 // but we have to check.
9963 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9964 }
9965}
9966
9967
9968/**
9969 * A helper function that visits elements of a JSArray in numerical
9970 * order.
9971 *
9972 * The visitor argument called for each existing element in the array
9973 * with the element index and the element's value.
9974 * Afterwards it increments the base-index of the visitor by the array
9975 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009976 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009977 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009978static bool IterateElements(Isolate* isolate,
9979 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009980 ArrayConcatVisitor* visitor) {
9981 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9982 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009983 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009984 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009985 // Run through the elements FixedArray and use HasElement and GetElement
9986 // to check the prototype for missing elements.
9987 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9988 int fast_length = static_cast<int>(length);
9989 ASSERT(fast_length <= elements->length());
9990 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009991 HandleScope loop_scope(isolate);
9992 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009993 if (!element_value->IsTheHole()) {
9994 visitor->visit(j, element_value);
9995 } else if (receiver->HasElement(j)) {
9996 // Call GetElement on receiver, not its prototype, or getters won't
9997 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009998 element_value = Object::GetElement(receiver, j);
9999 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010000 visitor->visit(j, element_value);
10001 }
10002 }
10003 break;
10004 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010005 case FAST_DOUBLE_ELEMENTS: {
10006 // TODO(1810): Decide if it's worthwhile to implement this.
10007 UNREACHABLE();
10008 break;
10009 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010010 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010011 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010012 List<uint32_t> indices(dict->Capacity() / 2);
10013 // Collect all indices in the object and the prototypes less
10014 // than length. This might introduce duplicates in the indices list.
10015 CollectElementIndices(receiver, length, &indices);
10016 indices.Sort(&compareUInt32);
10017 int j = 0;
10018 int n = indices.length();
10019 while (j < n) {
10020 HandleScope loop_scope;
10021 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010022 Handle<Object> element = Object::GetElement(receiver, index);
10023 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010024 visitor->visit(index, element);
10025 // Skip to next different index (i.e., omit duplicates).
10026 do {
10027 j++;
10028 } while (j < n && indices[j] == index);
10029 }
10030 break;
10031 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010032 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010033 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
10034 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010035 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010036 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010037 visitor->visit(j, e);
10038 }
10039 break;
10040 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010041 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010042 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010043 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010044 break;
10045 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010046 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010047 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010048 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010049 break;
10050 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010051 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010052 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010053 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010054 break;
10055 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010056 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010057 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010058 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010059 break;
10060 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010061 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010062 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010063 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010064 break;
10065 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010066 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010067 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010068 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010069 break;
10070 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010071 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010072 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010073 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010074 break;
10075 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010076 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010077 IterateExternalArrayElements<ExternalDoubleArray, double>(
10078 isolate, receiver, false, false, visitor);
10079 break;
10080 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010081 default:
10082 UNREACHABLE();
10083 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010084 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010085 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010086 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010087}
10088
10089
10090/**
10091 * Array::concat implementation.
10092 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010093 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010094 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010095 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010096RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010097 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010098 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010099
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010100 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10101 int argument_count = static_cast<int>(arguments->length()->Number());
10102 RUNTIME_ASSERT(arguments->HasFastElements());
10103 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010104
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010105 // Pass 1: estimate the length and number of elements of the result.
10106 // The actual length can be larger if any of the arguments have getters
10107 // that mutate other arguments (but will otherwise be precise).
10108 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010109
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010110 uint32_t estimate_result_length = 0;
10111 uint32_t estimate_nof_elements = 0;
10112 {
10113 for (int i = 0; i < argument_count; i++) {
10114 HandleScope loop_scope;
10115 Handle<Object> obj(elements->get(i));
10116 uint32_t length_estimate;
10117 uint32_t element_estimate;
10118 if (obj->IsJSArray()) {
10119 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010120 // TODO(1810): Find out if it's worthwhile to properly support
10121 // arbitrary ElementsKinds. For now, pessimistically transition to
10122 // FAST_ELEMENTS.
10123 if (array->HasFastDoubleElements()) {
10124 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010125 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010126 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010127 length_estimate =
10128 static_cast<uint32_t>(array->length()->Number());
10129 element_estimate =
10130 EstimateElementCount(array);
10131 } else {
10132 length_estimate = 1;
10133 element_estimate = 1;
10134 }
10135 // Avoid overflows by capping at kMaxElementCount.
10136 if (JSObject::kMaxElementCount - estimate_result_length <
10137 length_estimate) {
10138 estimate_result_length = JSObject::kMaxElementCount;
10139 } else {
10140 estimate_result_length += length_estimate;
10141 }
10142 if (JSObject::kMaxElementCount - estimate_nof_elements <
10143 element_estimate) {
10144 estimate_nof_elements = JSObject::kMaxElementCount;
10145 } else {
10146 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010147 }
10148 }
10149 }
10150
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010151 // If estimated number of elements is more than half of length, a
10152 // fixed array (fast case) is more time and space-efficient than a
10153 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010154 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010155
10156 Handle<FixedArray> storage;
10157 if (fast_case) {
10158 // The backing storage array must have non-existing elements to
10159 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010160 storage = isolate->factory()->NewFixedArrayWithHoles(
10161 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010162 } else {
10163 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10164 uint32_t at_least_space_for = estimate_nof_elements +
10165 (estimate_nof_elements >> 2);
10166 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010167 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010168 }
10169
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010170 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010171
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010172 for (int i = 0; i < argument_count; i++) {
10173 Handle<Object> obj(elements->get(i));
10174 if (obj->IsJSArray()) {
10175 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010176 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010177 return Failure::Exception();
10178 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010179 } else {
10180 visitor.visit(0, obj);
10181 visitor.increase_index_offset(1);
10182 }
10183 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010184
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010185 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010186}
10187
10188
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010189// This will not allocate (flatten the string), but it may run
10190// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010191RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010192 NoHandleAllocation ha;
10193 ASSERT(args.length() == 1);
10194
10195 CONVERT_CHECKED(String, string, args[0]);
10196 StringInputBuffer buffer(string);
10197 while (buffer.has_more()) {
10198 uint16_t character = buffer.GetNext();
10199 PrintF("%c", character);
10200 }
10201 return string;
10202}
10203
ager@chromium.org5ec48922009-05-05 07:25:34 +000010204// Moves all own elements of an object, that are below a limit, to positions
10205// starting at zero. All undefined values are placed after non-undefined values,
10206// and are followed by non-existing element. Does not change the length
10207// property.
10208// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010209RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010210 ASSERT(args.length() == 2);
10211 CONVERT_CHECKED(JSObject, object, args[0]);
10212 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10213 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010214}
10215
10216
10217// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010218RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010219 ASSERT(args.length() == 2);
10220 CONVERT_CHECKED(JSArray, from, args[0]);
10221 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010222 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010223 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010224 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010225 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10226 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010227 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010228 } else if (new_elements->map() ==
10229 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010230 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010231 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010232 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010233 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010234 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010235 Object* new_map;
10236 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010237 to->set_map(Map::cast(new_map));
10238 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010239 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010240 Object* obj;
10241 { MaybeObject* maybe_obj = from->ResetElements();
10242 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10243 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010244 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245 return to;
10246}
10247
10248
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010249// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010250RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010251 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010252 CONVERT_CHECKED(JSObject, object, args[0]);
10253 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010254 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010255 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10256 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010257 } else if (object->IsJSArray()) {
10258 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010259 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010260 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010261 }
10262}
10263
10264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010265RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010266 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010267
10268 ASSERT_EQ(3, args.length());
10269
ager@chromium.orgac091b72010-05-05 07:34:42 +000010270 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010271 Handle<Object> key1 = args.at<Object>(1);
10272 Handle<Object> key2 = args.at<Object>(2);
10273
10274 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010275 if (!key1->ToArrayIndex(&index1)
10276 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010277 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010278 }
10279
ager@chromium.orgac091b72010-05-05 07:34:42 +000010280 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010281 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010282 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010283 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010284 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010285
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010286 RETURN_IF_EMPTY_HANDLE(
10287 isolate, JSObject::SetElement(jsobject, index1, tmp2, kStrictMode));
10288 RETURN_IF_EMPTY_HANDLE(
10289 isolate, JSObject::SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010290
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010291 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010292}
10293
10294
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010295// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010296// might have elements. Can either return keys (positive integers) or
10297// intervals (pair of a negative integer (-start-1) followed by a
10298// positive (length)) or undefined values.
10299// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010300RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010301 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010302 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010303 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010304 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010305 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010306 // Create an array and get all the keys into it, then remove all the
10307 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010308 bool threw = false;
10309 Handle<FixedArray> keys =
10310 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10311 if (threw) return Failure::Exception();
10312
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010313 int keys_length = keys->length();
10314 for (int i = 0; i < keys_length; i++) {
10315 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010316 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010317 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010318 // Zap invalid keys.
10319 keys->set_undefined(i);
10320 }
10321 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010322 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010323 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010324 ASSERT(array->HasFastElements() ||
10325 array->HasFastSmiOnlyElements() ||
10326 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010327 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010328 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010329 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010330 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010331 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010332 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010333 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010334 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010335 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010336 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010337 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010338 }
10339}
10340
10341
10342// DefineAccessor takes an optional final argument which is the
ulan@chromium.org2efb9002012-01-19 15:36:35 +000010343// property attributes (e.g. DONT_ENUM, DONT_DELETE). IMPORTANT: due
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010344// to the way accessors are implemented, it is set for both the getter
10345// and setter on the first call to DefineAccessor and ignored on
10346// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010347RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010348 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10349 // Compute attributes.
10350 PropertyAttributes attributes = NONE;
10351 if (args.length() == 5) {
10352 CONVERT_CHECKED(Smi, attrs, args[4]);
10353 int value = attrs->value();
10354 // Only attribute bits should be set.
10355 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10356 attributes = static_cast<PropertyAttributes>(value);
10357 }
10358
10359 CONVERT_CHECKED(JSObject, obj, args[0]);
10360 CONVERT_CHECKED(String, name, args[1]);
10361 CONVERT_CHECKED(Smi, flag, args[2]);
10362 CONVERT_CHECKED(JSFunction, fun, args[3]);
10363 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10364}
10365
10366
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010367RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010368 ASSERT(args.length() == 3);
10369 CONVERT_CHECKED(JSObject, obj, args[0]);
10370 CONVERT_CHECKED(String, name, args[1]);
10371 CONVERT_CHECKED(Smi, flag, args[2]);
10372 return obj->LookupAccessor(name, flag->value() == 0);
10373}
10374
10375
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010376#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010377RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010378 ASSERT(args.length() == 0);
10379 return Execution::DebugBreakHelper();
10380}
10381
10382
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010383// Helper functions for wrapping and unwrapping stack frame ids.
10384static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010385 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010386 return Smi::FromInt(id >> 2);
10387}
10388
10389
10390static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10391 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10392}
10393
10394
10395// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010396// args[0]: debug event listener function to set or null or undefined for
10397// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010398// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010399RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010400 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010401 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10402 args[0]->IsUndefined() ||
10403 args[0]->IsNull());
10404 Handle<Object> callback = args.at<Object>(0);
10405 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010406 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010407
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010408 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010409}
10410
10411
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010412RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010413 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010414 isolate->stack_guard()->DebugBreak();
10415 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010416}
10417
10418
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010419static MaybeObject* DebugLookupResultValue(Heap* heap,
10420 Object* receiver,
10421 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010422 LookupResult* result,
10423 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010424 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010425 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010426 case NORMAL:
10427 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010428 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010429 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010430 }
10431 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010432 case FIELD:
10433 value =
10434 JSObject::cast(
10435 result->holder())->FastPropertyAt(result->GetFieldIndex());
10436 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010437 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010438 }
10439 return value;
10440 case CONSTANT_FUNCTION:
10441 return result->GetConstantFunction();
10442 case CALLBACKS: {
10443 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010444 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010445 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10446 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010447 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010448 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010449 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010450 maybe_value = heap->isolate()->pending_exception();
10451 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010452 if (caught_exception != NULL) {
10453 *caught_exception = true;
10454 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010455 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010456 }
10457 return value;
10458 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010459 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010460 }
10461 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010462 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010463 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010464 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010465 case CONSTANT_TRANSITION:
10466 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010467 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010468 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010469 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010470 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010471 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010472 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010473 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010474}
10475
10476
ager@chromium.org32912102009-01-16 10:38:43 +000010477// Get debugger related details for an object property.
10478// args[0]: object holding property
10479// args[1]: name of the property
10480//
10481// The array returned contains the following information:
10482// 0: Property value
10483// 1: Property details
10484// 2: Property value is exception
10485// 3: Getter function if defined
10486// 4: Setter function if defined
10487// Items 2-4 are only filled if the property has either a getter or a setter
10488// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010489RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010490 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010491
10492 ASSERT(args.length() == 2);
10493
10494 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10495 CONVERT_ARG_CHECKED(String, name, 1);
10496
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010497 // Make sure to set the current context to the context before the debugger was
10498 // entered (if the debugger is entered). The reason for switching context here
10499 // is that for some property lookups (accessors and interceptors) callbacks
10500 // into the embedding application can occour, and the embedding application
10501 // could have the assumption that its own global context is the current
10502 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010503 SaveContext save(isolate);
10504 if (isolate->debug()->InDebugger()) {
10505 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010506 }
10507
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010508 // Skip the global proxy as it has no properties and always delegates to the
10509 // real global object.
10510 if (obj->IsJSGlobalProxy()) {
10511 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10512 }
10513
10514
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010515 // Check if the name is trivially convertible to an index and get the element
10516 // if so.
10517 uint32_t index;
10518 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010519 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010520 Object* element_or_char;
10521 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010522 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010523 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10524 return maybe_element_or_char;
10525 }
10526 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010527 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010528 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010529 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010530 }
10531
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010532 // Find the number of objects making up this.
10533 int length = LocalPrototypeChainLength(*obj);
10534
10535 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010536 Handle<JSObject> jsproto = obj;
10537 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010538 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010539 jsproto->LocalLookup(*name, &result);
10540 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010541 // LookupResult is not GC safe as it holds raw object pointers.
10542 // GC can happen later in this code so put the required fields into
10543 // local variables using handles when required for later use.
10544 PropertyType result_type = result.type();
10545 Handle<Object> result_callback_obj;
10546 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010547 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10548 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010549 }
10550 Smi* property_details = result.GetPropertyDetails().AsSmi();
10551 // DebugLookupResultValue can cause GC so details from LookupResult needs
10552 // to be copied to handles before this.
10553 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010554 Object* raw_value;
10555 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010556 DebugLookupResultValue(isolate->heap(), *obj, *name,
10557 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010558 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10559 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010560 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010561
10562 // If the callback object is a fixed array then it contains JavaScript
10563 // getter and/or setter.
10564 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010565 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010566 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010567 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010568 details->set(0, *value);
10569 details->set(1, property_details);
10570 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010571 details->set(2, isolate->heap()->ToBoolean(caught_exception));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010572 details->set(3, AccessorPair::cast(*result_callback_obj)->getter());
10573 details->set(4, AccessorPair::cast(*result_callback_obj)->setter());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010574 }
10575
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010576 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010577 }
10578 if (i < length - 1) {
10579 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10580 }
10581 }
10582
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010583 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010584}
10585
10586
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010587RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010588 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010589
10590 ASSERT(args.length() == 2);
10591
10592 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10593 CONVERT_ARG_CHECKED(String, name, 1);
10594
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010595 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010596 obj->Lookup(*name, &result);
10597 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010598 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010599 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010600 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010601}
10602
10603
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010604// Return the property type calculated from the property details.
10605// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010606RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010607 ASSERT(args.length() == 1);
10608 CONVERT_CHECKED(Smi, details, args[0]);
10609 PropertyType type = PropertyDetails(details).type();
10610 return Smi::FromInt(static_cast<int>(type));
10611}
10612
10613
10614// Return the property attribute calculated from the property details.
10615// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010616RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010617 ASSERT(args.length() == 1);
10618 CONVERT_CHECKED(Smi, details, args[0]);
10619 PropertyAttributes attributes = PropertyDetails(details).attributes();
10620 return Smi::FromInt(static_cast<int>(attributes));
10621}
10622
10623
10624// Return the property insertion index calculated from the property details.
10625// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010626RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010627 ASSERT(args.length() == 1);
10628 CONVERT_CHECKED(Smi, details, args[0]);
10629 int index = PropertyDetails(details).index();
10630 return Smi::FromInt(index);
10631}
10632
10633
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010634// Return property value from named interceptor.
10635// args[0]: object
10636// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010637RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010638 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010639 ASSERT(args.length() == 2);
10640 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10641 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10642 CONVERT_ARG_CHECKED(String, name, 1);
10643
10644 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010645 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010646}
10647
10648
10649// Return element value from indexed interceptor.
10650// args[0]: object
10651// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010652RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010653 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010654 ASSERT(args.length() == 2);
10655 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10656 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10657 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10658
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010659 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010660}
10661
10662
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010663RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010664 ASSERT(args.length() >= 1);
10665 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010666 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010667 if (isolate->debug()->break_id() == 0 ||
10668 break_id != isolate->debug()->break_id()) {
10669 return isolate->Throw(
10670 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010671 }
10672
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010673 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010674}
10675
10676
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010677RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010678 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010679 ASSERT(args.length() == 1);
10680
10681 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010682 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010683 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10684 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010685 if (!maybe_result->ToObject(&result)) return maybe_result;
10686 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010687
10688 // Count all frames which are relevant to debugging stack trace.
10689 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010690 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010691 if (id == StackFrame::NO_ID) {
10692 // If there is no JavaScript stack frame count is 0.
10693 return Smi::FromInt(0);
10694 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010695
10696 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10697 n += it.frame()->GetInlineCount();
10698 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010699 return Smi::FromInt(n);
10700}
10701
10702
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010703class FrameInspector {
10704 public:
10705 FrameInspector(JavaScriptFrame* frame,
10706 int inlined_frame_index,
10707 Isolate* isolate)
10708 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10709 // Calculate the deoptimized frame.
10710 if (frame->is_optimized()) {
10711 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10712 frame, inlined_frame_index, isolate);
10713 }
10714 has_adapted_arguments_ = frame_->has_adapted_arguments();
10715 is_optimized_ = frame_->is_optimized();
10716 }
10717
10718 ~FrameInspector() {
10719 // Get rid of the calculated deoptimized frame if any.
10720 if (deoptimized_frame_ != NULL) {
10721 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10722 isolate_);
10723 }
10724 }
10725
10726 int GetParametersCount() {
10727 return is_optimized_
10728 ? deoptimized_frame_->parameters_count()
10729 : frame_->ComputeParametersCount();
10730 }
10731 int expression_count() { return deoptimized_frame_->expression_count(); }
10732 Object* GetFunction() {
10733 return is_optimized_
10734 ? deoptimized_frame_->GetFunction()
10735 : frame_->function();
10736 }
10737 Object* GetParameter(int index) {
10738 return is_optimized_
10739 ? deoptimized_frame_->GetParameter(index)
10740 : frame_->GetParameter(index);
10741 }
10742 Object* GetExpression(int index) {
10743 return is_optimized_
10744 ? deoptimized_frame_->GetExpression(index)
10745 : frame_->GetExpression(index);
10746 }
10747
10748 // To inspect all the provided arguments the frame might need to be
10749 // replaced with the arguments frame.
10750 void SetArgumentsFrame(JavaScriptFrame* frame) {
10751 ASSERT(has_adapted_arguments_);
10752 frame_ = frame;
10753 is_optimized_ = frame_->is_optimized();
10754 ASSERT(!is_optimized_);
10755 }
10756
10757 private:
10758 JavaScriptFrame* frame_;
10759 DeoptimizedFrameInfo* deoptimized_frame_;
10760 Isolate* isolate_;
10761 bool is_optimized_;
10762 bool has_adapted_arguments_;
10763
10764 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10765};
10766
10767
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010768static const int kFrameDetailsFrameIdIndex = 0;
10769static const int kFrameDetailsReceiverIndex = 1;
10770static const int kFrameDetailsFunctionIndex = 2;
10771static const int kFrameDetailsArgumentCountIndex = 3;
10772static const int kFrameDetailsLocalCountIndex = 4;
10773static const int kFrameDetailsSourcePositionIndex = 5;
10774static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010775static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010776static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010777static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010778
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010779
10780static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10781 JavaScriptFrame* frame) {
10782 SaveContext* save = isolate->save_context();
10783 while (save != NULL && !save->IsBelowFrame(frame)) {
10784 save = save->prev();
10785 }
10786 ASSERT(save != NULL);
10787 return save;
10788}
10789
10790
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010791// Return an array with frame details
10792// args[0]: number: break id
10793// args[1]: number: frame index
10794//
10795// The array returned contains the following information:
10796// 0: Frame id
10797// 1: Receiver
10798// 2: Function
10799// 3: Argument count
10800// 4: Local count
10801// 5: Source position
10802// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010803// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010804// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010805// Arguments name, value
10806// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010807// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010808RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010809 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010810 ASSERT(args.length() == 2);
10811
10812 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010813 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010814 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10815 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010816 if (!maybe_check->ToObject(&check)) return maybe_check;
10817 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010818 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010819 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010820
10821 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010822 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010823 if (id == StackFrame::NO_ID) {
10824 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010825 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010826 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010827
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010828 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010829
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010830 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010831 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010832 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010833 if (index < count + it.frame()->GetInlineCount()) break;
10834 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010835 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010836 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010837
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010838 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010839 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010840 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010841 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010842 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010843
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010844 // Traverse the saved contexts chain to find the active context for the
10845 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010846 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010847
10848 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010849 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010850
10851 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010852 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010853 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010854
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010855 // Check for constructor frame. Inlined frames cannot be construct calls.
10856 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010857 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010858 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010859
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010860 // Get scope info and read from it for local variable information.
10861 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010862 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010863 Handle<ScopeInfo> scope_info(shared->scope_info());
10864 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010865
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010866 // Get the locals names and values into a temporary array.
10867 //
10868 // TODO(1240907): Hide compiler-introduced stack variables
10869 // (e.g. .result)? For users of the debugger, they will probably be
10870 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010871 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010872 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010874 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010875 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010876 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010877 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010878 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010879 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010880 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010881 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010882 // Get the context containing declarations.
10883 Handle<Context> context(
10884 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010885 for (; i < scope_info->LocalCount(); ++i) {
10886 Handle<String> name(scope_info->LocalName(i));
10887 VariableMode mode;
10888 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010889 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010890 locals->set(i * 2 + 1, context->get(
10891 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010892 }
10893 }
10894
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010895 // Check whether this frame is positioned at return. If not top
10896 // frame or if the frame is optimized it cannot be at a return.
10897 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010898 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010899 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010900 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010901
10902 // If positioned just before return find the value to be returned and add it
10903 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010904 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010905 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010906 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010907 Address internal_frame_sp = NULL;
10908 while (!it2.done()) {
10909 if (it2.frame()->is_internal()) {
10910 internal_frame_sp = it2.frame()->sp();
10911 } else {
10912 if (it2.frame()->is_java_script()) {
10913 if (it2.frame()->id() == it.frame()->id()) {
10914 // The internal frame just before the JavaScript frame contains the
10915 // value to return on top. A debug break at return will create an
10916 // internal frame to store the return value (eax/rax/r0) before
10917 // entering the debug break exit frame.
10918 if (internal_frame_sp != NULL) {
10919 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010920 Handle<Object>(Memory::Object_at(internal_frame_sp),
10921 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010922 break;
10923 }
10924 }
10925 }
10926
10927 // Indicate that the previous frame was not an internal frame.
10928 internal_frame_sp = NULL;
10929 }
10930 it2.Advance();
10931 }
10932 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010933
10934 // Now advance to the arguments adapter frame (if any). It contains all
10935 // the provided parameters whereas the function frame always have the number
10936 // of arguments matching the functions parameters. The rest of the
10937 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010938 if (it.frame()->has_adapted_arguments()) {
10939 it.AdvanceToArgumentsFrame();
10940 frame_inspector.SetArgumentsFrame(it.frame());
10941 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010942
10943 // Find the number of arguments to fill. At least fill the number of
10944 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010945 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010946 if (argument_count < frame_inspector.GetParametersCount()) {
10947 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010948 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010949#ifdef DEBUG
10950 if (it.frame()->is_optimized()) {
10951 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10952 }
10953#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010954
10955 // Calculate the size of the result.
10956 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010957 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010958 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010959 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010960
10961 // Add the frame id.
10962 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10963
10964 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010965 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010966
10967 // Add the arguments count.
10968 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10969
10970 // Add the locals count
10971 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010972 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010973
10974 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010975 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010976 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10977 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010978 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010979 }
10980
10981 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010982 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010983
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010984 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010985 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010986
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010987 // Add flags to indicate information on whether this frame is
10988 // bit 0: invoked in the debugger context.
10989 // bit 1: optimized frame.
10990 // bit 2: inlined in optimized frame
10991 int flags = 0;
10992 if (*save->context() == *isolate->debug()->debug_context()) {
10993 flags |= 1 << 0;
10994 }
10995 if (it.frame()->is_optimized()) {
10996 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010997 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010998 }
10999 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011000
11001 // Fill the dynamic part.
11002 int details_index = kFrameDetailsFirstDynamicIndex;
11003
11004 // Add arguments name and value.
11005 for (int i = 0; i < argument_count; i++) {
11006 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011007 if (i < scope_info->ParameterCount()) {
11008 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011009 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011010 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011011 }
11012
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011013 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011014 if (i < it.frame()->ComputeParametersCount()) {
11015 // Get the value from the stack.
11016 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011017 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011018 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011019 }
11020 }
11021
11022 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011023 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011024 details->set(details_index++, locals->get(i));
11025 }
11026
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011027 // Add the value being returned.
11028 if (at_return) {
11029 details->set(details_index++, *return_value);
11030 }
11031
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011032 // Add the receiver (same as in function frame).
11033 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
11034 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011035 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011036 if (!receiver->IsJSObject() &&
11037 shared->is_classic_mode() &&
11038 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000011039 // If the receiver is not a JSObject and the function is not a
11040 // builtin or strict-mode we have hit an optimization where a
11041 // value object is not converted into a wrapped JS objects. To
11042 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011043 // by creating correct wrapper object based on the calling frame's
11044 // global context.
11045 it.Advance();
11046 Handle<Context> calling_frames_global_context(
11047 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011048 receiver =
11049 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011050 }
11051 details->set(kFrameDetailsReceiverIndex, *receiver);
11052
11053 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011054 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011055}
11056
11057
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011058// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011059static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011060 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011061 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011062 Handle<Context> context,
11063 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011064 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011065 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11066 VariableMode mode;
11067 InitializationFlag init_flag;
11068 int context_index = scope_info->ContextSlotIndex(
11069 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011070
whesse@chromium.org7b260152011-06-20 15:33:18 +000011071 RETURN_IF_EMPTY_HANDLE_VALUE(
11072 isolate,
11073 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011074 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011075 Handle<Object>(context->get(context_index), isolate),
11076 NONE,
11077 kNonStrictMode),
11078 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011079 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011080
11081 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011082}
11083
11084
11085// Create a plain JSObject which materializes the local scope for the specified
11086// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011087static Handle<JSObject> MaterializeLocalScope(
11088 Isolate* isolate,
11089 JavaScriptFrame* frame,
11090 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011091 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011092 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011093 Handle<ScopeInfo> scope_info(shared->scope_info());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011094 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011095
11096 // Allocate and initialize a JSObject with all the arguments, stack locals
11097 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011098 Handle<JSObject> local_scope =
11099 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011100
11101 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011102 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011103 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011104 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011105 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011106 Handle<String>(scope_info->ParameterName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011107 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011108 NONE,
11109 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011110 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011111 }
11112
11113 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011114 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011115 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011116 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011117 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011118 Handle<String>(scope_info->StackLocalName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011119 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011120 NONE,
11121 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011122 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011123 }
11124
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011125 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011126 // Third fill all context locals.
11127 Handle<Context> frame_context(Context::cast(frame->context()));
11128 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011129 if (!CopyContextLocalsToScopeObject(
11130 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011131 return Handle<JSObject>();
11132 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011133
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011134 // Finally copy any properties from the function context extension.
11135 // These will be variables introduced by eval.
11136 if (function_context->closure() == *function) {
11137 if (function_context->has_extension() &&
11138 !function_context->IsGlobalContext()) {
11139 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011140 bool threw = false;
11141 Handle<FixedArray> keys =
11142 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11143 if (threw) return Handle<JSObject>();
11144
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011145 for (int i = 0; i < keys->length(); i++) {
11146 // Names of variables introduced by eval are strings.
11147 ASSERT(keys->get(i)->IsString());
11148 Handle<String> key(String::cast(keys->get(i)));
11149 RETURN_IF_EMPTY_HANDLE_VALUE(
11150 isolate,
11151 SetProperty(local_scope,
11152 key,
11153 GetProperty(ext, key),
11154 NONE,
11155 kNonStrictMode),
11156 Handle<JSObject>());
11157 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011158 }
11159 }
11160 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011161
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011162 return local_scope;
11163}
11164
11165
11166// Create a plain JSObject which materializes the closure content for the
11167// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011168static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11169 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011170 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011171
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011172 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011173 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011174
ulan@chromium.org2efb9002012-01-19 15:36:35 +000011175 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011176 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011177 Handle<JSObject> closure_scope =
11178 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011179
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011180 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011181 if (!CopyContextLocalsToScopeObject(
11182 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011183 return Handle<JSObject>();
11184 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011185
11186 // Finally copy any properties from the function context extension. This will
11187 // be variables introduced by eval.
11188 if (context->has_extension()) {
11189 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011190 bool threw = false;
11191 Handle<FixedArray> keys =
11192 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11193 if (threw) return Handle<JSObject>();
11194
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011195 for (int i = 0; i < keys->length(); i++) {
11196 // Names of variables introduced by eval are strings.
11197 ASSERT(keys->get(i)->IsString());
11198 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011199 RETURN_IF_EMPTY_HANDLE_VALUE(
11200 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011201 SetProperty(closure_scope,
11202 key,
11203 GetProperty(ext, key),
11204 NONE,
11205 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011206 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011207 }
11208 }
11209
11210 return closure_scope;
11211}
11212
11213
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011214// Create a plain JSObject which materializes the scope for the specified
11215// catch context.
11216static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11217 Handle<Context> context) {
11218 ASSERT(context->IsCatchContext());
11219 Handle<String> name(String::cast(context->extension()));
11220 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11221 Handle<JSObject> catch_scope =
11222 isolate->factory()->NewJSObject(isolate->object_function());
11223 RETURN_IF_EMPTY_HANDLE_VALUE(
11224 isolate,
11225 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11226 Handle<JSObject>());
11227 return catch_scope;
11228}
11229
11230
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011231// Create a plain JSObject which materializes the block scope for the specified
11232// block context.
11233static Handle<JSObject> MaterializeBlockScope(
11234 Isolate* isolate,
11235 Handle<Context> context) {
11236 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011237 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011238
11239 // Allocate and initialize a JSObject with all the arguments, stack locals
11240 // heap locals and extension properties of the debugged function.
11241 Handle<JSObject> block_scope =
11242 isolate->factory()->NewJSObject(isolate->object_function());
11243
11244 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011245 if (!CopyContextLocalsToScopeObject(
11246 isolate, scope_info, context, block_scope)) {
11247 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011248 }
11249
11250 return block_scope;
11251}
11252
11253
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011254// Iterate over the actual scopes visible from a stack frame. The iteration
11255// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011256// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011257// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011258class ScopeIterator {
11259 public:
11260 enum ScopeType {
11261 ScopeTypeGlobal = 0,
11262 ScopeTypeLocal,
11263 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011264 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011265 ScopeTypeCatch,
11266 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011267 };
11268
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011269 ScopeIterator(Isolate* isolate,
11270 JavaScriptFrame* frame,
11271 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011272 : isolate_(isolate),
11273 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011274 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011275 function_(JSFunction::cast(frame->function())),
11276 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011277 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011278
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011279 // Catch the case when the debugger stops in an internal function.
11280 Handle<SharedFunctionInfo> shared_info(function_->shared());
11281 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11282 if (shared_info->script() == isolate->heap()->undefined_value()) {
11283 while (context_->closure() == *function_) {
11284 context_ = Handle<Context>(context_->previous(), isolate_);
11285 }
11286 return;
11287 }
11288
11289 // Get the debug info (create it if it does not exist).
11290 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11291 // Return if ensuring debug info failed.
11292 return;
11293 }
11294 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11295
11296 // Find the break point where execution has stopped.
11297 BreakLocationIterator break_location_iterator(debug_info,
11298 ALL_BREAK_LOCATIONS);
11299 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11300 if (break_location_iterator.IsExit()) {
11301 // We are within the return sequence. At the momemt it is not possible to
11302 // get a source position which is consistent with the current scope chain.
11303 // Thus all nested with, catch and block contexts are skipped and we only
11304 // provide the function scope.
11305 if (scope_info->HasContext()) {
11306 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11307 } else {
11308 while (context_->closure() == *function_) {
11309 context_ = Handle<Context>(context_->previous(), isolate_);
11310 }
11311 }
11312 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11313 } else {
11314 // Reparse the code and analyze the scopes.
11315 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11316 Handle<Script> script(Script::cast(shared_info->script()));
11317 Scope* scope = NULL;
11318
11319 // Check whether we are in global, eval or function code.
11320 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11321 if (scope_info->Type() != FUNCTION_SCOPE) {
11322 // Global or eval code.
11323 CompilationInfo info(script);
11324 if (scope_info->Type() == GLOBAL_SCOPE) {
11325 info.MarkAsGlobal();
11326 } else {
11327 ASSERT(scope_info->Type() == EVAL_SCOPE);
11328 info.MarkAsEval();
11329 info.SetCallingContext(Handle<Context>(function_->context()));
11330 }
11331 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11332 scope = info.function()->scope();
11333 }
11334 } else {
11335 // Function code
11336 CompilationInfo info(shared_info);
11337 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11338 scope = info.function()->scope();
11339 }
11340 }
11341
11342 // Retrieve the scope chain for the current position.
11343 if (scope != NULL) {
11344 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11345 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11346 } else {
11347 // A failed reparse indicates that the preparser has diverged from the
11348 // parser or that the preparse data given to the initial parse has been
11349 // faulty. We fail in debug mode but in release mode we only provide the
11350 // information we get from the context chain but nothing about
11351 // completely stack allocated scopes or stack allocated locals.
11352 UNREACHABLE();
11353 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011354 }
11355 }
11356
11357 // More scopes?
11358 bool Done() { return context_.is_null(); }
11359
11360 // Move to the next scope.
11361 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011362 ScopeType scope_type = Type();
11363 if (scope_type == ScopeTypeGlobal) {
11364 // The global scope is always the last in the chain.
11365 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011366 context_ = Handle<Context>();
11367 return;
11368 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011369 if (nested_scope_chain_.is_empty()) {
11370 context_ = Handle<Context>(context_->previous(), isolate_);
11371 } else {
11372 if (nested_scope_chain_.last()->HasContext()) {
11373 ASSERT(context_->previous() != NULL);
11374 context_ = Handle<Context>(context_->previous(), isolate_);
11375 }
11376 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011377 }
11378 }
11379
11380 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011381 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011382 if (!nested_scope_chain_.is_empty()) {
11383 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11384 switch (scope_info->Type()) {
11385 case FUNCTION_SCOPE:
11386 ASSERT(context_->IsFunctionContext() ||
11387 !scope_info->HasContext());
11388 return ScopeTypeLocal;
11389 case GLOBAL_SCOPE:
11390 ASSERT(context_->IsGlobalContext());
11391 return ScopeTypeGlobal;
11392 case WITH_SCOPE:
11393 ASSERT(context_->IsWithContext());
11394 return ScopeTypeWith;
11395 case CATCH_SCOPE:
11396 ASSERT(context_->IsCatchContext());
11397 return ScopeTypeCatch;
11398 case BLOCK_SCOPE:
11399 ASSERT(!scope_info->HasContext() ||
11400 context_->IsBlockContext());
11401 return ScopeTypeBlock;
11402 case EVAL_SCOPE:
11403 UNREACHABLE();
11404 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011405 }
11406 if (context_->IsGlobalContext()) {
11407 ASSERT(context_->global()->IsGlobalObject());
11408 return ScopeTypeGlobal;
11409 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011410 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011411 return ScopeTypeClosure;
11412 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011413 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011414 return ScopeTypeCatch;
11415 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011416 if (context_->IsBlockContext()) {
11417 return ScopeTypeBlock;
11418 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011419 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011420 return ScopeTypeWith;
11421 }
11422
11423 // Return the JavaScript object with the content of the current scope.
11424 Handle<JSObject> ScopeObject() {
11425 switch (Type()) {
11426 case ScopeIterator::ScopeTypeGlobal:
11427 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011428 case ScopeIterator::ScopeTypeLocal:
11429 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011430 ASSERT(nested_scope_chain_.length() == 1);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011431 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011432 case ScopeIterator::ScopeTypeWith:
11433 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011434 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11435 case ScopeIterator::ScopeTypeCatch:
11436 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011437 case ScopeIterator::ScopeTypeClosure:
11438 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011439 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011440 case ScopeIterator::ScopeTypeBlock:
11441 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011442 }
11443 UNREACHABLE();
11444 return Handle<JSObject>();
11445 }
11446
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011447 Handle<ScopeInfo> CurrentScopeInfo() {
11448 if (!nested_scope_chain_.is_empty()) {
11449 return nested_scope_chain_.last();
11450 } else if (context_->IsBlockContext()) {
11451 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11452 } else if (context_->IsFunctionContext()) {
11453 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11454 }
11455 return Handle<ScopeInfo>::null();
11456 }
11457
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011458 // Return the context for this scope. For the local context there might not
11459 // be an actual context.
11460 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011461 if (Type() == ScopeTypeGlobal ||
11462 nested_scope_chain_.is_empty()) {
11463 return context_;
11464 } else if (nested_scope_chain_.last()->HasContext()) {
11465 return context_;
11466 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011467 return Handle<Context>();
11468 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011469 }
11470
11471#ifdef DEBUG
11472 // Debug print of the content of the current scope.
11473 void DebugPrint() {
11474 switch (Type()) {
11475 case ScopeIterator::ScopeTypeGlobal:
11476 PrintF("Global:\n");
11477 CurrentContext()->Print();
11478 break;
11479
11480 case ScopeIterator::ScopeTypeLocal: {
11481 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011482 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011483 if (!CurrentContext().is_null()) {
11484 CurrentContext()->Print();
11485 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011486 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011487 if (extension->IsJSContextExtensionObject()) {
11488 extension->Print();
11489 }
11490 }
11491 }
11492 break;
11493 }
11494
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011495 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011496 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011497 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011498 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011499
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011500 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011501 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011502 CurrentContext()->extension()->Print();
11503 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011504 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011505
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011506 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011507 PrintF("Closure:\n");
11508 CurrentContext()->Print();
11509 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011510 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011511 if (extension->IsJSContextExtensionObject()) {
11512 extension->Print();
11513 }
11514 }
11515 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011516
11517 default:
11518 UNREACHABLE();
11519 }
11520 PrintF("\n");
11521 }
11522#endif
11523
11524 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011525 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011526 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011527 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011528 Handle<JSFunction> function_;
11529 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011530 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011531
11532 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11533};
11534
11535
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011536RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011537 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011538 ASSERT(args.length() == 2);
11539
11540 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011541 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011542 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11543 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011544 if (!maybe_check->ToObject(&check)) return maybe_check;
11545 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011546 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11547
11548 // Get the frame where the debugging is performed.
11549 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011550 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011551 JavaScriptFrame* frame = it.frame();
11552
11553 // Count the visible scopes.
11554 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011555 for (ScopeIterator it(isolate, frame, 0);
11556 !it.Done();
11557 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011558 n++;
11559 }
11560
11561 return Smi::FromInt(n);
11562}
11563
11564
11565static const int kScopeDetailsTypeIndex = 0;
11566static const int kScopeDetailsObjectIndex = 1;
11567static const int kScopeDetailsSize = 2;
11568
11569// Return an array with scope details
11570// args[0]: number: break id
11571// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011572// args[2]: number: inlined frame index
11573// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011574//
11575// The array returned contains the following information:
11576// 0: Scope type
11577// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011578RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011579 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011580 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011581
11582 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011583 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011584 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11585 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011586 if (!maybe_check->ToObject(&check)) return maybe_check;
11587 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011588 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011589 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11590 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011591
11592 // Get the frame where the debugging is performed.
11593 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011594 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011595 JavaScriptFrame* frame = frame_it.frame();
11596
11597 // Find the requested scope.
11598 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011599 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011600 for (; !it.Done() && n < index; it.Next()) {
11601 n++;
11602 }
11603 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011604 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011605 }
11606
11607 // Calculate the size of the result.
11608 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011609 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011610
11611 // Fill in scope details.
11612 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011613 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011614 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011615 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011616
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011617 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011618}
11619
11620
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011621RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011622 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011623 ASSERT(args.length() == 0);
11624
11625#ifdef DEBUG
11626 // Print the scopes for the top frame.
11627 StackFrameLocator locator;
11628 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011629 for (ScopeIterator it(isolate, frame, 0);
11630 !it.Done();
11631 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011632 it.DebugPrint();
11633 }
11634#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011635 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011636}
11637
11638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011639RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011640 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011641 ASSERT(args.length() == 1);
11642
11643 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011644 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011645 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11646 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011647 if (!maybe_result->ToObject(&result)) return maybe_result;
11648 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011649
11650 // Count all archived V8 threads.
11651 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011652 for (ThreadState* thread =
11653 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011654 thread != NULL;
11655 thread = thread->Next()) {
11656 n++;
11657 }
11658
11659 // Total number of threads is current thread and archived threads.
11660 return Smi::FromInt(n + 1);
11661}
11662
11663
11664static const int kThreadDetailsCurrentThreadIndex = 0;
11665static const int kThreadDetailsThreadIdIndex = 1;
11666static const int kThreadDetailsSize = 2;
11667
11668// Return an array with thread details
11669// args[0]: number: break id
11670// args[1]: number: thread index
11671//
11672// The array returned contains the following information:
11673// 0: Is current thread?
11674// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011675RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011676 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011677 ASSERT(args.length() == 2);
11678
11679 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011680 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011681 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11682 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011683 if (!maybe_check->ToObject(&check)) return maybe_check;
11684 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011685 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11686
11687 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011688 Handle<FixedArray> details =
11689 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011690
11691 // Thread index 0 is current thread.
11692 if (index == 0) {
11693 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011694 details->set(kThreadDetailsCurrentThreadIndex,
11695 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011696 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011697 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011698 } else {
11699 // Find the thread with the requested index.
11700 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011701 ThreadState* thread =
11702 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011703 while (index != n && thread != NULL) {
11704 thread = thread->Next();
11705 n++;
11706 }
11707 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011708 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011709 }
11710
11711 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011712 details->set(kThreadDetailsCurrentThreadIndex,
11713 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011714 details->set(kThreadDetailsThreadIdIndex,
11715 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011716 }
11717
11718 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011719 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011720}
11721
11722
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011723// Sets the disable break state
11724// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011725RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011726 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011727 ASSERT(args.length() == 1);
11728 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011729 isolate->debug()->set_disable_break(disable_break);
11730 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011731}
11732
11733
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011734RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011735 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011736 ASSERT(args.length() == 1);
11737
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011738 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11739 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011740 // Find the number of break points
11741 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011742 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011743 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011744 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011745 Handle<FixedArray>::cast(break_locations));
11746}
11747
11748
11749// Set a break point in a function
11750// args[0]: function
11751// args[1]: number: break source position (within the function source)
11752// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011753RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011754 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011755 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011756 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11757 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011758 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11759 RUNTIME_ASSERT(source_position >= 0);
11760 Handle<Object> break_point_object_arg = args.at<Object>(2);
11761
11762 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011763 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11764 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011765
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011766 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011767}
11768
11769
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011770Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11771 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011772 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011773 // Iterate the heap looking for SharedFunctionInfo generated from the
11774 // script. The inner most SharedFunctionInfo containing the source position
11775 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011776 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011777 // which is found is not compiled it is compiled and the heap is iterated
11778 // again as the compilation might create inner functions from the newly
11779 // compiled function and the actual requested break point might be in one of
11780 // these functions.
11781 bool done = false;
11782 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011783 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011784 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011785 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011786 { // Extra scope for iterator and no-allocation.
11787 isolate->heap()->EnsureHeapIsIterable();
11788 AssertNoAllocation no_alloc_during_heap_iteration;
11789 HeapIterator iterator;
11790 for (HeapObject* obj = iterator.next();
11791 obj != NULL; obj = iterator.next()) {
11792 if (obj->IsSharedFunctionInfo()) {
11793 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11794 if (shared->script() == *script) {
11795 // If the SharedFunctionInfo found has the requested script data and
11796 // contains the source position it is a candidate.
11797 int start_position = shared->function_token_position();
11798 if (start_position == RelocInfo::kNoPosition) {
11799 start_position = shared->start_position();
11800 }
11801 if (start_position <= position &&
11802 position <= shared->end_position()) {
11803 // If there is no candidate or this function is within the current
11804 // candidate this is the new candidate.
11805 if (target.is_null()) {
11806 target_start_position = start_position;
11807 target = shared;
11808 } else {
11809 if (target_start_position == start_position &&
11810 shared->end_position() == target->end_position()) {
11811 // If a top-level function contain only one function
11812 // declartion the source for the top-level and the
11813 // function is the same. In that case prefer the non
11814 // top-level function.
11815 if (!shared->is_toplevel()) {
11816 target_start_position = start_position;
11817 target = shared;
11818 }
11819 } else if (target_start_position <= start_position &&
11820 shared->end_position() <= target->end_position()) {
11821 // This containment check includes equality as a function
11822 // inside a top-level function can share either start or end
11823 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011824 target_start_position = start_position;
11825 target = shared;
11826 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011827 }
11828 }
11829 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011830 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011831 } // End for loop.
11832 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011833
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011834 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011835 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011836 }
11837
11838 // If the candidate found is compiled we are done. NOTE: when lazy
11839 // compilation of inner functions is introduced some additional checking
11840 // needs to be done here to compile inner functions.
11841 done = target->is_compiled();
11842 if (!done) {
11843 // If the candidate is not compiled compile it to reveal any inner
11844 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011845 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011846 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011847 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011848
11849 return *target;
11850}
11851
11852
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011853// Changes the state of a break point in a script and returns source position
11854// where break point was set. NOTE: Regarding performance see the NOTE for
11855// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011856// args[0]: script to set break point in
11857// args[1]: number: break source position (within the script source)
11858// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011859RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011860 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011861 ASSERT(args.length() == 3);
11862 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11863 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11864 RUNTIME_ASSERT(source_position >= 0);
11865 Handle<Object> break_point_object_arg = args.at<Object>(2);
11866
11867 // Get the script from the script wrapper.
11868 RUNTIME_ASSERT(wrapper->value()->IsScript());
11869 Handle<Script> script(Script::cast(wrapper->value()));
11870
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011871 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011872 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011873 if (!result->IsUndefined()) {
11874 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11875 // Find position within function. The script position might be before the
11876 // source position of the first function.
11877 int position;
11878 if (shared->start_position() > source_position) {
11879 position = 0;
11880 } else {
11881 position = source_position - shared->start_position();
11882 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011883 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011884 position += shared->start_position();
11885 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011886 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011887 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011888}
11889
11890
11891// Clear a break point
11892// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011893RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011894 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011895 ASSERT(args.length() == 1);
11896 Handle<Object> break_point_object_arg = args.at<Object>(0);
11897
11898 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011899 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011900
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011901 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011902}
11903
11904
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011905// Change the state of break on exceptions.
11906// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11907// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011908RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011909 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011910 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011911 RUNTIME_ASSERT(args[0]->IsNumber());
11912 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011913
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011914 // If the number doesn't match an enum value, the ChangeBreakOnException
11915 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011916 ExceptionBreakType type =
11917 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011918 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011919 isolate->debug()->ChangeBreakOnException(type, enable);
11920 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011921}
11922
11923
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011924// Returns the state of break on exceptions
11925// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011926RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011927 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011928 ASSERT(args.length() == 1);
11929 RUNTIME_ASSERT(args[0]->IsNumber());
11930
11931 ExceptionBreakType type =
11932 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011933 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011934 return Smi::FromInt(result);
11935}
11936
11937
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011938// Prepare for stepping
11939// args[0]: break id for checking execution state
11940// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011941// args[2]: number of times to perform the step, for step out it is the number
11942// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011943RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011944 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011945 ASSERT(args.length() == 3);
11946 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011947 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011948 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11949 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011950 if (!maybe_check->ToObject(&check)) return maybe_check;
11951 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011952 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011953 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011954 }
11955
11956 // Get the step action and check validity.
11957 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11958 if (step_action != StepIn &&
11959 step_action != StepNext &&
11960 step_action != StepOut &&
11961 step_action != StepInMin &&
11962 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011963 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011964 }
11965
11966 // Get the number of steps.
11967 int step_count = NumberToInt32(args[2]);
11968 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011969 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011970 }
11971
ager@chromium.orga1645e22009-09-09 19:27:10 +000011972 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011973 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011974
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011975 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011976 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11977 step_count);
11978 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011979}
11980
11981
11982// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011983RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011984 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011985 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011986 isolate->debug()->ClearStepping();
11987 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011988}
11989
11990
11991// Creates a copy of the with context chain. The copy of the context chain is
11992// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011993static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11994 Handle<JSFunction> function,
11995 Handle<Context> base,
11996 JavaScriptFrame* frame,
11997 int inlined_frame_index) {
11998 HandleScope scope(isolate);
11999 List<Handle<ScopeInfo> > scope_chain;
12000 List<Handle<Context> > context_chain;
12001
12002 ScopeIterator it(isolate, frame, inlined_frame_index);
12003 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
12004 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
12005 ASSERT(!it.Done());
12006 scope_chain.Add(it.CurrentScopeInfo());
12007 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012008 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012009
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012010 // At the end of the chain. Return the base context to link to.
12011 Handle<Context> context = base;
12012
12013 // Iteratively copy and or materialize the nested contexts.
12014 while (!scope_chain.is_empty()) {
12015 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
12016 Handle<Context> current = context_chain.RemoveLast();
12017 ASSERT(!(scope_info->HasContext() & current.is_null()));
12018
12019 if (scope_info->Type() == CATCH_SCOPE) {
12020 Handle<String> name(String::cast(current->extension()));
12021 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
12022 context =
12023 isolate->factory()->NewCatchContext(function,
12024 context,
12025 name,
12026 thrown_object);
12027 } else if (scope_info->Type() == BLOCK_SCOPE) {
12028 // Materialize the contents of the block scope into a JSObject.
12029 Handle<JSObject> block_scope_object =
12030 MaterializeBlockScope(isolate, current);
12031 if (block_scope_object.is_null()) {
12032 return Handle<Context>::null();
12033 }
12034 // Allocate a new function context for the debug evaluation and set the
12035 // extension object.
12036 Handle<Context> new_context =
12037 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12038 function);
12039 new_context->set_extension(*block_scope_object);
12040 new_context->set_previous(*context);
12041 context = new_context;
12042 } else {
12043 ASSERT(scope_info->Type() == WITH_SCOPE);
12044 ASSERT(current->IsWithContext());
12045 Handle<JSObject> extension(JSObject::cast(current->extension()));
12046 context =
12047 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000012048 }
erikcorry0ad885c2011-11-21 13:51:57 +000012049 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012050
12051 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012052}
12053
12054
12055// Helper function to find or create the arguments object for
12056// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012057static Handle<Object> GetArgumentsObject(Isolate* isolate,
12058 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012059 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012060 Handle<JSFunction> function,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012061 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012062 Handle<Context> function_context) {
12063 // Try to find the value of 'arguments' to pass as parameter. If it is not
12064 // found (that is the debugged function does not reference 'arguments' and
12065 // does not support eval) then create an 'arguments' object.
12066 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012067 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012068 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012069 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012070 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012071 }
12072 }
12073
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012074 if (scope_info->HasHeapAllocatedLocals()) {
12075 VariableMode mode;
12076 InitializationFlag init_flag;
12077 index = scope_info->ContextSlotIndex(
12078 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012079 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012080 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012081 }
12082 }
12083
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012084 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
12085
12086 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012087 Handle<JSObject> arguments =
12088 isolate->factory()->NewArgumentsObject(function, length);
12089 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012090
12091 AssertNoAllocation no_gc;
12092 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012093 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012094 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012095 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012096 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012097 return arguments;
12098}
12099
12100
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012101static const char kSourceStr[] =
12102 "(function(arguments,__source__){return eval(__source__);})";
12103
12104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012105// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012106// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012107// extension part has all the parameters and locals of the function on the
12108// stack frame. A function which calls eval with the code to evaluate is then
12109// compiled in this context and called in this context. As this context
12110// replaces the context of the function on the stack frame a new (empty)
12111// function is created as well to be used as the closure for the context.
12112// This function and the context acts as replacements for the function on the
12113// stack frame presenting the same view of the values of parameters and
12114// local variables as if the piece of JavaScript was evaluated at the point
12115// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012116RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012117 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012118
12119 // Check the execution state and decode arguments frame and source to be
12120 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012121 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012122 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012123 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12124 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012125 if (!maybe_check_result->ToObject(&check_result)) {
12126 return maybe_check_result;
12127 }
12128 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012129 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012130 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
12131 CONVERT_ARG_CHECKED(String, source, 3);
12132 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
12133 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012134
12135 // Handle the processing of break.
12136 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012137
12138 // Get the frame where the debugging is performed.
12139 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012140 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012141 JavaScriptFrame* frame = it.frame();
12142 Handle<JSFunction> function(JSFunction::cast(frame->function()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012143 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012144
12145 // Traverse the saved contexts chain to find the active context for the
12146 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012147 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12148
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012149 SaveContext savex(isolate);
12150 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012151
12152 // Create the (empty) function replacing the function on the stack frame for
12153 // the purpose of evaluating in the context created below. It is important
12154 // that this function does not describe any parameters and local variables
12155 // in the context. If it does then this will cause problems with the lookup
12156 // in Context::Lookup, where context slots for parameters and local variables
12157 // are looked at before the extension object.
12158 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012159 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12160 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012161 go_between->set_context(function->context());
12162#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012163 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12164 ASSERT(go_between_scope_info->ParameterCount() == 0);
12165 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012166#endif
12167
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012168 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012169 Handle<JSObject> local_scope = MaterializeLocalScope(
12170 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012171 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012172
12173 // Allocate a new context for the debug evaluation and set the extension
12174 // object build.
12175 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012176 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12177 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012178 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012179 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012180 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012181 Handle<Context> function_context;
12182 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012183 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012184 function_context = Handle<Context>(frame_context->declaration_context());
12185 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012186 context = CopyNestedScopeContextChain(isolate,
12187 go_between,
12188 context,
12189 frame,
12190 inlined_frame_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012191
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012192 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012193 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012194 context =
12195 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012196 }
12197
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012198 // Wrap the evaluation statement in a new function compiled in the newly
12199 // created context. The function has one parameter which has to be called
12200 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012201 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012202 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012203
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012204 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012205 isolate->factory()->NewStringFromAscii(
12206 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012207
12208 // Currently, the eval code will be executed in non-strict mode,
12209 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012210 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012211 Compiler::CompileEval(function_source,
12212 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012213 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012214 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012215 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012216 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012217 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012218 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012219
12220 // Invoke the result of the compilation to get the evaluation function.
12221 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012222 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012223 Handle<Object> evaluation_function =
12224 Execution::Call(compiled_function, receiver, 0, NULL,
12225 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012226 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012227
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012228 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012229 frame,
12230 inlined_frame_index,
12231 function,
12232 scope_info,
12233 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012234
12235 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012236 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012237 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012238 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12239 receiver,
12240 ARRAY_SIZE(argv),
12241 argv,
12242 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012243 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012244
12245 // Skip the global proxy as it has no properties and always delegates to the
12246 // real global object.
12247 if (result->IsJSGlobalProxy()) {
12248 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12249 }
12250
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012251 return *result;
12252}
12253
12254
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012255RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012256 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012257
12258 // Check the execution state and decode arguments frame and source to be
12259 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012260 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012261 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012262 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12263 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012264 if (!maybe_check_result->ToObject(&check_result)) {
12265 return maybe_check_result;
12266 }
12267 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012268 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012269 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012270 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012271
12272 // Handle the processing of break.
12273 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012274
12275 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012276 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012277 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012278 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012279 top = top->prev();
12280 }
12281 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012282 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012283 }
12284
12285 // Get the global context now set to the top context from before the
12286 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012287 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012288
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012289 bool is_global = true;
12290
12291 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012292 // Create a new with context with the additional context information between
12293 // the context of the debugged function and the eval code to be executed.
12294 context = isolate->factory()->NewWithContext(
12295 Handle<JSFunction>(context->closure()),
12296 context,
12297 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012298 is_global = false;
12299 }
12300
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012301 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012302 // Currently, the eval code will be executed in non-strict mode,
12303 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012304 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012305 Compiler::CompileEval(source,
12306 context,
12307 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012308 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012309 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012310 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012311 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012312 Handle<JSFunction>(
12313 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12314 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012315
12316 // Invoke the result of the compilation to get the evaluation function.
12317 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012318 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012319 Handle<Object> result =
12320 Execution::Call(compiled_function, receiver, 0, NULL,
12321 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012322 // Clear the oneshot breakpoints so that the debugger does not step further.
12323 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012324 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012325 return *result;
12326}
12327
12328
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012329RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012330 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012331 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012332
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012333 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012334 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012335
12336 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012337 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012338 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12339 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12340 // because using
12341 // instances->set(i, *GetScriptWrapper(script))
12342 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012343 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012344 Handle<JSValue> wrapper = GetScriptWrapper(script);
12345 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012346 }
12347
12348 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012349 Handle<JSObject> result =
12350 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012351 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012352 return *result;
12353}
12354
12355
12356// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012357static int DebugReferencedBy(HeapIterator* iterator,
12358 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012359 Object* instance_filter, int max_references,
12360 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012361 JSFunction* arguments_function) {
12362 NoHandleAllocation ha;
12363 AssertNoAllocation no_alloc;
12364
12365 // Iterate the heap.
12366 int count = 0;
12367 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012368 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012369 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012370 (max_references == 0 || count < max_references)) {
12371 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012372 if (heap_obj->IsJSObject()) {
12373 // Skip context extension objects and argument arrays as these are
12374 // checked in the context of functions using them.
12375 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012376 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012377 obj->map()->constructor() == arguments_function) {
12378 continue;
12379 }
12380
12381 // Check if the JS object has a reference to the object looked for.
12382 if (obj->ReferencesObject(target)) {
12383 // Check instance filter if supplied. This is normally used to avoid
12384 // references from mirror objects (see Runtime_IsInPrototypeChain).
12385 if (!instance_filter->IsUndefined()) {
12386 Object* V = obj;
12387 while (true) {
12388 Object* prototype = V->GetPrototype();
12389 if (prototype->IsNull()) {
12390 break;
12391 }
12392 if (instance_filter == prototype) {
12393 obj = NULL; // Don't add this object.
12394 break;
12395 }
12396 V = prototype;
12397 }
12398 }
12399
12400 if (obj != NULL) {
12401 // Valid reference found add to instance array if supplied an update
12402 // count.
12403 if (instances != NULL && count < instances_size) {
12404 instances->set(count, obj);
12405 }
12406 last = obj;
12407 count++;
12408 }
12409 }
12410 }
12411 }
12412
12413 // Check for circular reference only. This can happen when the object is only
12414 // referenced from mirrors and has a circular reference in which case the
12415 // object is not really alive and would have been garbage collected if not
12416 // referenced from the mirror.
12417 if (count == 1 && last == target) {
12418 count = 0;
12419 }
12420
12421 // Return the number of referencing objects found.
12422 return count;
12423}
12424
12425
12426// Scan the heap for objects with direct references to an object
12427// args[0]: the object to find references to
12428// args[1]: constructor function for instances to exclude (Mirror)
12429// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012430RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012431 ASSERT(args.length() == 3);
12432
12433 // First perform a full GC in order to avoid references from dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012434 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12435 // The heap iterator reserves the right to do a GC to make the heap iterable.
12436 // Due to the GC above we know it won't need to do that, but it seems cleaner
12437 // to get the heap iterator constructed before we start having unprotected
12438 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012439
12440 // Check parameters.
12441 CONVERT_CHECKED(JSObject, target, args[0]);
12442 Object* instance_filter = args[1];
12443 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12444 instance_filter->IsJSObject());
12445 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12446 RUNTIME_ASSERT(max_references >= 0);
12447
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012448
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012449 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012450 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012451 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012452 JSFunction* arguments_function =
12453 JSFunction::cast(arguments_boilerplate->map()->constructor());
12454
12455 // Get the number of referencing objects.
12456 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012457 HeapIterator heap_iterator;
12458 count = DebugReferencedBy(&heap_iterator,
12459 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012460 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012461
12462 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012463 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012464 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012465 if (!maybe_object->ToObject(&object)) return maybe_object;
12466 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012467 FixedArray* instances = FixedArray::cast(object);
12468
12469 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012470 // AllocateFixedArray above does not make the heap non-iterable.
12471 ASSERT(HEAP->IsHeapIterable());
12472 HeapIterator heap_iterator2;
12473 count = DebugReferencedBy(&heap_iterator2,
12474 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012475 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012476
12477 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012478 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012479 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012480 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012481 if (!maybe_result->ToObject(&result)) return maybe_result;
12482 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012483}
12484
12485
12486// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012487static int DebugConstructedBy(HeapIterator* iterator,
12488 JSFunction* constructor,
12489 int max_references,
12490 FixedArray* instances,
12491 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012492 AssertNoAllocation no_alloc;
12493
12494 // Iterate the heap.
12495 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012496 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012497 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012498 (max_references == 0 || count < max_references)) {
12499 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012500 if (heap_obj->IsJSObject()) {
12501 JSObject* obj = JSObject::cast(heap_obj);
12502 if (obj->map()->constructor() == constructor) {
12503 // Valid reference found add to instance array if supplied an update
12504 // count.
12505 if (instances != NULL && count < instances_size) {
12506 instances->set(count, obj);
12507 }
12508 count++;
12509 }
12510 }
12511 }
12512
12513 // Return the number of referencing objects found.
12514 return count;
12515}
12516
12517
12518// Scan the heap for objects constructed by a specific function.
12519// args[0]: the constructor to find instances of
12520// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012521RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012522 ASSERT(args.length() == 2);
12523
12524 // First perform a full GC in order to avoid dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012525 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012526
12527 // Check parameters.
12528 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12529 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12530 RUNTIME_ASSERT(max_references >= 0);
12531
12532 // Get the number of referencing objects.
12533 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012534 HeapIterator heap_iterator;
12535 count = DebugConstructedBy(&heap_iterator,
12536 constructor,
12537 max_references,
12538 NULL,
12539 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012540
12541 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012542 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012543 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012544 if (!maybe_object->ToObject(&object)) return maybe_object;
12545 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012546 FixedArray* instances = FixedArray::cast(object);
12547
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012548 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012549 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012550 HeapIterator heap_iterator2;
12551 count = DebugConstructedBy(&heap_iterator2,
12552 constructor,
12553 max_references,
12554 instances,
12555 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012556
12557 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012558 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012559 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12560 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012561 if (!maybe_result->ToObject(&result)) return maybe_result;
12562 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012563 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012564}
12565
12566
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012567// Find the effective prototype object as returned by __proto__.
12568// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012569RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012570 ASSERT(args.length() == 1);
12571
12572 CONVERT_CHECKED(JSObject, obj, args[0]);
12573
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012574 // Use the __proto__ accessor.
12575 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012576}
12577
12578
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012579RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012580 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012581 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012582 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012583}
12584
12585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012586RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012587#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012588 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012589 ASSERT(args.length() == 1);
12590 // Get the function and make sure it is compiled.
12591 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012592 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012593 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012594 return Failure::Exception();
12595 }
12596 func->code()->PrintLn();
12597#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012598 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012599}
ager@chromium.org9085a012009-05-11 19:22:57 +000012600
12601
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012602RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012603#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012604 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012605 ASSERT(args.length() == 1);
12606 // Get the function and make sure it is compiled.
12607 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012608 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012609 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012610 return Failure::Exception();
12611 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012612 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012613#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012614 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012615}
12616
12617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012618RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012619 NoHandleAllocation ha;
12620 ASSERT(args.length() == 1);
12621
12622 CONVERT_CHECKED(JSFunction, f, args[0]);
12623 return f->shared()->inferred_name();
12624}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012625
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012626
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012627static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12628 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012629 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012630 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012631 int counter = 0;
12632 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012633 for (HeapObject* obj = iterator->next();
12634 obj != NULL;
12635 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012636 ASSERT(obj != NULL);
12637 if (!obj->IsSharedFunctionInfo()) {
12638 continue;
12639 }
12640 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12641 if (shared->script() != script) {
12642 continue;
12643 }
12644 if (counter < buffer_size) {
12645 buffer->set(counter, shared);
12646 }
12647 counter++;
12648 }
12649 return counter;
12650}
12651
12652// For a script finds all SharedFunctionInfo's in the heap that points
12653// to this script. Returns JSArray of SharedFunctionInfo wrapped
12654// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012655RUNTIME_FUNCTION(MaybeObject*,
12656 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012657 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012658 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012659 CONVERT_CHECKED(JSValue, script_value, args[0]);
12660
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012661
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012662 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12663
12664 const int kBufferSize = 32;
12665
12666 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012667 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012668 int number;
12669 {
12670 isolate->heap()->EnsureHeapIsIterable();
12671 AssertNoAllocation no_allocations;
12672 HeapIterator heap_iterator;
12673 Script* scr = *script;
12674 FixedArray* arr = *array;
12675 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12676 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012677 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012678 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012679 isolate->heap()->EnsureHeapIsIterable();
12680 AssertNoAllocation no_allocations;
12681 HeapIterator heap_iterator;
12682 Script* scr = *script;
12683 FixedArray* arr = *array;
12684 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012685 }
12686
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012687 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012688 result->set_length(Smi::FromInt(number));
12689
12690 LiveEdit::WrapSharedFunctionInfos(result);
12691
12692 return *result;
12693}
12694
12695// For a script calculates compilation information about all its functions.
12696// The script source is explicitly specified by the second argument.
12697// The source of the actual script is not used, however it is important that
12698// all generated code keeps references to this particular instance of script.
12699// Returns a JSArray of compilation infos. The array is ordered so that
12700// each function with all its descendant is always stored in a continues range
12701// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012702RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012703 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012704 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012705 CONVERT_CHECKED(JSValue, script, args[0]);
12706 CONVERT_ARG_CHECKED(String, source, 1);
12707 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12708
12709 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12710
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012711 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012712 return Failure::Exception();
12713 }
12714
12715 return result;
12716}
12717
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012718// Changes the source of the script to a new_source.
12719// If old_script_name is provided (i.e. is a String), also creates a copy of
12720// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012721RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012722 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012723 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012724 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12725 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012726 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012727
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012728 CONVERT_CHECKED(Script, original_script_pointer,
12729 original_script_value->value());
12730 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012731
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012732 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12733 new_source,
12734 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012735
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012736 if (old_script->IsScript()) {
12737 Handle<Script> script_handle(Script::cast(old_script));
12738 return *(GetScriptWrapper(script_handle));
12739 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012740 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012741 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012742}
12743
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012744
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012745RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012746 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012747 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012748 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12749 return LiveEdit::FunctionSourceUpdated(shared_info);
12750}
12751
12752
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012753// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012754RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012755 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012756 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012757 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12758 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12759
ager@chromium.orgac091b72010-05-05 07:34:42 +000012760 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012761}
12762
12763// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012764RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012765 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012766 HandleScope scope(isolate);
12767 Handle<Object> function_object(args[0], isolate);
12768 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012769
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012770 if (function_object->IsJSValue()) {
12771 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12772 if (script_object->IsJSValue()) {
12773 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012774 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012775 }
12776
12777 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12778 } else {
12779 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12780 // and we check it in this function.
12781 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012782
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012783 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012784}
12785
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012786
12787// In a code of a parent function replaces original function as embedded object
12788// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012789RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012790 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012791 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012792
12793 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12794 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12795 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12796
12797 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12798 subst_wrapper);
12799
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012800 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012801}
12802
12803
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012804// Updates positions of a shared function info (first parameter) according
12805// to script source change. Text change is described in second parameter as
12806// array of groups of 3 numbers:
12807// (change_begin, change_end, change_end_new_position).
12808// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012809RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012810 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012811 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012812 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12813 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12814
ager@chromium.orgac091b72010-05-05 07:34:42 +000012815 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012816}
12817
12818
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012819// For array of SharedFunctionInfo's (each wrapped in JSValue)
12820// checks that none of them have activations on stacks (of any thread).
12821// Returns array of the same length with corresponding results of
12822// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012823RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012824 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012825 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012826 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012827 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012828
ager@chromium.org357bf652010-04-12 11:30:10 +000012829 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012830}
12831
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012832// Compares 2 strings line-by-line, then token-wise and returns diff in form
12833// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12834// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012835RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012836 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012837 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012838 CONVERT_ARG_CHECKED(String, s1, 0);
12839 CONVERT_ARG_CHECKED(String, s2, 1);
12840
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012841 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012842}
12843
12844
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012845// A testing entry. Returns statement position which is the closest to
12846// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012847RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012848 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012849 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012850 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12851 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012853 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012854
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012855 if (code->kind() != Code::FUNCTION &&
12856 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012857 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012858 }
12859
12860 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012861 int closest_pc = 0;
12862 int distance = kMaxInt;
12863 while (!it.done()) {
12864 int statement_position = static_cast<int>(it.rinfo()->data());
12865 // Check if this break point is closer that what was previously found.
12866 if (source_position <= statement_position &&
12867 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012868 closest_pc =
12869 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012870 distance = statement_position - source_position;
12871 // Check whether we can't get any closer.
12872 if (distance == 0) break;
12873 }
12874 it.next();
12875 }
12876
12877 return Smi::FromInt(closest_pc);
12878}
12879
12880
ager@chromium.org357bf652010-04-12 11:30:10 +000012881// Calls specified function with or without entering the debugger.
12882// This is used in unit tests to run code as if debugger is entered or simply
12883// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012884RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012885 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012886 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012887 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12888 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12889
12890 Handle<Object> result;
12891 bool pending_exception;
12892 {
12893 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012894 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012895 &pending_exception);
12896 } else {
12897 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012898 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012899 &pending_exception);
12900 }
12901 }
12902 if (!pending_exception) {
12903 return *result;
12904 } else {
12905 return Failure::Exception();
12906 }
12907}
12908
12909
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012910// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012911RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012912 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012913 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012914 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12915 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012916 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012917}
12918
12919
12920// Performs a GC.
12921// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012922RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012923 isolate->heap()->CollectAllGarbage(true);
12924 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012925}
12926
12927
12928// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012929RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012930 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012931 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012932 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012933 }
12934 return Smi::FromInt(usage);
12935}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012936
12937
12938// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012939RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012940#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012941 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012942#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012943 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012944#endif
12945}
12946
12947
12948// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012949RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012950#ifdef LIVE_OBJECT_LIST
12951 return LiveObjectList::Capture();
12952#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012953 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012954#endif
12955}
12956
12957
12958// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012959RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012960#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012961 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012962 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012963 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012964#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012965 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012966#endif
12967}
12968
12969
12970// Generates the response to a debugger request for a dump of the objects
12971// contained in the difference between the captured live object lists
12972// specified by id1 and id2.
12973// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12974// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012975RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012976#ifdef LIVE_OBJECT_LIST
12977 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012978 CONVERT_SMI_ARG_CHECKED(id1, 0);
12979 CONVERT_SMI_ARG_CHECKED(id2, 1);
12980 CONVERT_SMI_ARG_CHECKED(start, 2);
12981 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012982 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12983 EnterDebugger enter_debugger;
12984 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12985#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012986 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012987#endif
12988}
12989
12990
12991// Gets the specified object as requested by the debugger.
12992// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012993RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012994#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012995 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012996 Object* result = LiveObjectList::GetObj(obj_id);
12997 return result;
12998#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012999 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013000#endif
13001}
13002
13003
13004// Gets the obj id for the specified address if valid.
13005// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013006RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013007#ifdef LIVE_OBJECT_LIST
13008 HandleScope scope;
13009 CONVERT_ARG_CHECKED(String, address, 0);
13010 Object* result = LiveObjectList::GetObjId(address);
13011 return result;
13012#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013013 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013014#endif
13015}
13016
13017
13018// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013019RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013020#ifdef LIVE_OBJECT_LIST
13021 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013022 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013023 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
13024 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
13025 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
13026 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
13027 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
13028
13029 Handle<JSObject> instance_filter;
13030 if (args[1]->IsJSObject()) {
13031 instance_filter = args.at<JSObject>(1);
13032 }
13033 bool verbose = false;
13034 if (args[2]->IsBoolean()) {
13035 verbose = args[2]->IsTrue();
13036 }
13037 int start = 0;
13038 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013039 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013040 }
13041 int limit = Smi::kMaxValue;
13042 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013043 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013044 }
13045
13046 return LiveObjectList::GetObjRetainers(obj_id,
13047 instance_filter,
13048 verbose,
13049 start,
13050 limit,
13051 filter_obj);
13052#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013053 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013054#endif
13055}
13056
13057
13058// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013059RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013060#ifdef LIVE_OBJECT_LIST
13061 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013062 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
13063 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013064 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
13065
13066 Handle<JSObject> instance_filter;
13067 if (args[2]->IsJSObject()) {
13068 instance_filter = args.at<JSObject>(2);
13069 }
13070
13071 Object* result =
13072 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
13073 return result;
13074#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013075 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013076#endif
13077}
13078
13079
13080// Generates the response to a debugger request for a list of all
13081// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013082RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013083#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013084 CONVERT_SMI_ARG_CHECKED(start, 0);
13085 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013086 return LiveObjectList::Info(start, count);
13087#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013088 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013089#endif
13090}
13091
13092
13093// Gets a dump of the specified object as requested by the debugger.
13094// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013095RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013096#ifdef LIVE_OBJECT_LIST
13097 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013098 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013099 Object* result = LiveObjectList::PrintObj(obj_id);
13100 return result;
13101#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013102 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013103#endif
13104}
13105
13106
13107// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013108RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013109#ifdef LIVE_OBJECT_LIST
13110 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013111 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013112#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013113 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013114#endif
13115}
13116
13117
13118// Generates the response to a debugger request for a summary of the types
13119// of objects in the difference between the captured live object lists
13120// specified by id1 and id2.
13121// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13122// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013123RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013124#ifdef LIVE_OBJECT_LIST
13125 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013126 CONVERT_SMI_ARG_CHECKED(id1, 0);
13127 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013128 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
13129
13130 EnterDebugger enter_debugger;
13131 return LiveObjectList::Summarize(id1, id2, filter_obj);
13132#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013133 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013134#endif
13135}
13136
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013137#endif // ENABLE_DEBUGGER_SUPPORT
13138
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013139
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013140RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013141 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013142 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013143 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013144}
13145
13146
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013147RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013148 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013149 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013150 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013151}
13152
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013153
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013154// Finds the script object from the script data. NOTE: This operation uses
13155// heap traversal to find the function generated for the source position
13156// for the requested break point. For lazily compiled functions several heap
13157// traversals might be required rendering this operation as a rather slow
13158// operation. However for setting break points which is normally done through
13159// some kind of user interaction the performance is not crucial.
13160static Handle<Object> Runtime_GetScriptFromScriptName(
13161 Handle<String> script_name) {
13162 // Scan the heap for Script objects to find the script with the requested
13163 // script data.
13164 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013165 script_name->GetHeap()->EnsureHeapIsIterable();
13166 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013167 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013168 HeapObject* obj = NULL;
13169 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013170 // If a script is found check if it has the script data requested.
13171 if (obj->IsScript()) {
13172 if (Script::cast(obj)->name()->IsString()) {
13173 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13174 script = Handle<Script>(Script::cast(obj));
13175 }
13176 }
13177 }
13178 }
13179
13180 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013181 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013182
13183 // Return the script found.
13184 return GetScriptWrapper(script);
13185}
13186
13187
13188// Get the script object from script data. NOTE: Regarding performance
13189// see the NOTE for GetScriptFromScriptData.
13190// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013191RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013192 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013193
13194 ASSERT(args.length() == 1);
13195
13196 CONVERT_CHECKED(String, script_name, args[0]);
13197
13198 // Find the requested script.
13199 Handle<Object> result =
13200 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13201 return *result;
13202}
13203
13204
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013205// Determines whether the given stack frame should be displayed in
13206// a stack trace. The caller is the error constructor that asked
13207// for the stack trace to be collected. The first time a construct
13208// call to this function is encountered it is skipped. The seen_caller
13209// in/out parameter is used to remember if the caller has been seen
13210// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013211static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13212 Object* caller,
13213 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013214 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013215 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013216 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013217 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013218 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13219 Object* raw_fun = frame->function();
13220 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013221 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013222 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013223 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013224 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013225 *seen_caller = true;
13226 return false;
13227 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013228 // Skip all frames until we've seen the caller.
13229 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013230 // Also, skip non-visible built-in functions and any call with the builtins
13231 // object as receiver, so as to not reveal either the builtins object or
13232 // an internal function.
13233 // The --builtins-in-stack-traces command line flag allows including
13234 // internal call sites in the stack trace for debugging purposes.
13235 if (!FLAG_builtins_in_stack_traces) {
13236 JSFunction* fun = JSFunction::cast(raw_fun);
13237 if (frame->receiver()->IsJSBuiltinsObject() ||
13238 (fun->IsBuiltin() && !fun->shared()->native())) {
13239 return false;
13240 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013241 }
13242 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013243}
13244
13245
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013246// Collect the raw data for a stack trace. Returns an array of 4
13247// element segments each containing a receiver, function, code and
13248// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013249RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013250 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013251 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013252 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
13253
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013254 HandleScope scope(isolate);
13255 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013256
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013257 limit = Max(limit, 0); // Ensure that limit is not negative.
13258 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013259 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013260 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013261
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013262 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013263 // If the caller parameter is a function we skip frames until we're
13264 // under it before starting to collect.
13265 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013266 int cursor = 0;
13267 int frames_seen = 0;
13268 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013269 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013270 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013271 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013272 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013273 // Set initial size to the maximum inlining level + 1 for the outermost
13274 // function.
13275 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013276 frame->Summarize(&frames);
13277 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013278 if (cursor + 4 > elements->length()) {
13279 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13280 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013281 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013282 for (int i = 0; i < cursor; i++) {
13283 new_elements->set(i, elements->get(i));
13284 }
13285 elements = new_elements;
13286 }
13287 ASSERT(cursor + 4 <= elements->length());
13288
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013289 Handle<Object> recv = frames[i].receiver();
13290 Handle<JSFunction> fun = frames[i].function();
13291 Handle<Code> code = frames[i].code();
13292 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013293 elements->set(cursor++, *recv);
13294 elements->set(cursor++, *fun);
13295 elements->set(cursor++, *code);
13296 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013297 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013298 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013299 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013300 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013301 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013302 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013303 return *result;
13304}
13305
13306
ager@chromium.org3811b432009-10-28 14:53:37 +000013307// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013308RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013309 ASSERT_EQ(args.length(), 0);
13310
13311 NoHandleAllocation ha;
13312
13313 const char* version_string = v8::V8::GetVersion();
13314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013315 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13316 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013317}
13318
13319
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013320RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013321 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013322 OS::PrintError("abort: %s\n",
13323 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013324 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013325 OS::Abort();
13326 UNREACHABLE();
13327 return NULL;
13328}
13329
13330
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013331RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013332 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013333 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013334 Object* key = args[1];
13335
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013336 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013337 Object* o = cache->get(finger_index);
13338 if (o == key) {
13339 // The fastest case: hit the same place again.
13340 return cache->get(finger_index + 1);
13341 }
13342
13343 for (int i = finger_index - 2;
13344 i >= JSFunctionResultCache::kEntriesIndex;
13345 i -= 2) {
13346 o = cache->get(i);
13347 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013348 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013349 return cache->get(i + 1);
13350 }
13351 }
13352
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013353 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013354 ASSERT(size <= cache->length());
13355
13356 for (int i = size - 2; i > finger_index; i -= 2) {
13357 o = cache->get(i);
13358 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013359 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013360 return cache->get(i + 1);
13361 }
13362 }
13363
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013364 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013365 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013366
13367 Handle<JSFunctionResultCache> cache_handle(cache);
13368 Handle<Object> key_handle(key);
13369 Handle<Object> value;
13370 {
13371 Handle<JSFunction> factory(JSFunction::cast(
13372 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13373 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013374 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013375 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013376 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013377 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013378 value = Execution::Call(factory,
13379 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013380 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013381 argv,
13382 &pending_exception);
13383 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013384 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013385
13386#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013387 if (FLAG_verify_heap) {
13388 cache_handle->JSFunctionResultCacheVerify();
13389 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013390#endif
13391
13392 // Function invocation may have cleared the cache. Reread all the data.
13393 finger_index = cache_handle->finger_index();
13394 size = cache_handle->size();
13395
13396 // If we have spare room, put new data into it, otherwise evict post finger
13397 // entry which is likely to be the least recently used.
13398 int index = -1;
13399 if (size < cache_handle->length()) {
13400 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13401 index = size;
13402 } else {
13403 index = finger_index + JSFunctionResultCache::kEntrySize;
13404 if (index == cache_handle->length()) {
13405 index = JSFunctionResultCache::kEntriesIndex;
13406 }
13407 }
13408
13409 ASSERT(index % 2 == 0);
13410 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13411 ASSERT(index < cache_handle->length());
13412
13413 cache_handle->set(index, *key_handle);
13414 cache_handle->set(index + 1, *value);
13415 cache_handle->set_finger_index(index);
13416
13417#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013418 if (FLAG_verify_heap) {
13419 cache_handle->JSFunctionResultCacheVerify();
13420 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013421#endif
13422
13423 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013424}
13425
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013426
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013427RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013428 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013429 CONVERT_ARG_CHECKED(String, type, 0);
13430 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013431 return *isolate->factory()->NewJSMessageObject(
13432 type,
13433 arguments,
13434 0,
13435 0,
13436 isolate->factory()->undefined_value(),
13437 isolate->factory()->undefined_value(),
13438 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013439}
13440
13441
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013442RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013443 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13444 return message->type();
13445}
13446
13447
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013448RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013449 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13450 return message->arguments();
13451}
13452
13453
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013454RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013455 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13456 return Smi::FromInt(message->start_position());
13457}
13458
13459
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013460RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013461 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13462 return message->script();
13463}
13464
13465
kasper.lund44510672008-07-25 07:37:58 +000013466#ifdef DEBUG
13467// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13468// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013469RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013470 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013471 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013472#define COUNT_ENTRY(Name, argc, ressize) + 1
13473 int entry_count = 0
13474 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13475 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13476 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13477#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013478 Factory* factory = isolate->factory();
13479 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013480 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013481 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013482#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013483 { \
13484 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013485 Handle<String> name; \
13486 /* Inline runtime functions have an underscore in front of the name. */ \
13487 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013488 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013489 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13490 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013491 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013492 Vector<const char>(#Name, StrLength(#Name))); \
13493 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013494 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013495 pair_elements->set(0, *name); \
13496 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013497 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013498 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013499 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013500 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013501 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013502 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013503 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013504 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013505#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013506 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013507 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013508 return *result;
13509}
kasper.lund44510672008-07-25 07:37:58 +000013510#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013511
13512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013513RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013514 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013515 CONVERT_CHECKED(String, format, args[0]);
13516 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013517 String::FlatContent format_content = format->GetFlatContent();
13518 RUNTIME_ASSERT(format_content.IsAscii());
13519 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013520 LOGGER->LogRuntime(chars, elms);
13521 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013522}
13523
13524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013525RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013526 UNREACHABLE(); // implemented as macro in the parser
13527 return NULL;
13528}
13529
13530
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013531#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13532 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13533 CONVERT_CHECKED(JSObject, obj, args[0]); \
13534 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13535 }
13536
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013537ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013538ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13539ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13540ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13541ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13542ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13543ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13544ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13545ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13546ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13547ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13548ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13549ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13550ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13551
13552#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13553
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013554
13555RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13556 ASSERT(args.length() == 2);
13557 CONVERT_CHECKED(JSObject, obj1, args[0]);
13558 CONVERT_CHECKED(JSObject, obj2, args[1]);
13559 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13560}
13561
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013562// ----------------------------------------------------------------------------
13563// Implementation of Runtime
13564
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013565#define F(name, number_of_args, result_size) \
13566 { Runtime::k##name, Runtime::RUNTIME, #name, \
13567 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013568
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013569
13570#define I(name, number_of_args, result_size) \
13571 { Runtime::kInline##name, Runtime::INLINE, \
13572 "_" #name, NULL, number_of_args, result_size },
13573
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013574static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013575 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013576 INLINE_FUNCTION_LIST(I)
13577 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013578};
13579
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013580
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013581MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13582 Object* dictionary) {
13583 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013584 ASSERT(dictionary != NULL);
13585 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13586 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013587 Object* name_symbol;
13588 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013589 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013590 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13591 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013592 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013593 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13594 String::cast(name_symbol),
13595 Smi::FromInt(i),
13596 PropertyDetails(NONE, NORMAL));
13597 if (!maybe_dictionary->ToObject(&dictionary)) {
13598 // Non-recoverable failure. Calling code must restart heap
13599 // initialization.
13600 return maybe_dictionary;
13601 }
13602 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013603 }
13604 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013605}
13606
13607
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013608const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13609 Heap* heap = name->GetHeap();
13610 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013611 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013612 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013613 int function_index = Smi::cast(smi_index)->value();
13614 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013615 }
13616 return NULL;
13617}
13618
13619
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013620const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013621 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13622}
13623
13624
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013625void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013626 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013627 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013628 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013629 if (isolate->heap()->new_space()->AddFreshPage()) {
13630 return;
13631 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013632 // Try to do a garbage collection; ignore it if it fails. The C
13633 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013634 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013635 } else {
13636 // Handle last resort GC and make sure to allow future allocations
13637 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013638 isolate->counters()->gc_last_resort_from_js()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013639 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013640 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013641}
13642
13643
13644} } // namespace v8::internal